diff options
Diffstat (limited to 'simulator')
| -rw-r--r-- | simulator/Dockerfile | 4 | ||||
| -rw-r--r-- | simulator/README.md | 34 | ||||
| -rw-r--r-- | simulator/build.gradle.kts | 6 | ||||
| -rw-r--r-- | simulator/buildSrc/build.gradle.kts | 4 | ||||
| -rw-r--r-- | simulator/buildSrc/src/main/kotlin/kotlin-library-convention.gradle.kts | 8 | ||||
| -rw-r--r-- | simulator/buildSrc/src/main/kotlin/library.kt | 2 | ||||
| -rw-r--r-- | simulator/gradle/wrapper/gradle-wrapper.jar | bin | 58910 -> 59203 bytes | |||
| -rw-r--r-- | simulator/gradle/wrapper/gradle-wrapper.properties | 2 | ||||
| -rwxr-xr-x | simulator/gradlew | 2 | ||||
| -rw-r--r-- | simulator/gradlew.bat | 21 | ||||
| -rw-r--r-- | simulator/odcsim/README.md | 54 | ||||
| -rw-r--r-- | simulator/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/Domain.kt | 54 | ||||
| -rw-r--r-- | simulator/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/SimulationEngineProvider.kt | 35 | ||||
| -rw-r--r-- | simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/OmegaSimulationEngine.kt | 264 | ||||
| -rw-r--r-- | simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/logging/LocationAwareLoggerImpl.kt | 567 | ||||
| -rw-r--r-- | simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/logging/LocationIgnorantLoggerImpl.kt | 440 | ||||
| -rw-r--r-- | simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/logging/LoggerImpl.kt | 74 | ||||
| -rw-r--r-- | simulator/odcsim/odcsim-engine-omega/src/main/resources/META-INF/services/com.atlarge.odcsim.SimulationEngineProvider | 1 | ||||
| -rw-r--r-- | simulator/opendc-compute/build.gradle.kts (renamed from simulator/opendc/build.gradle.kts) | 6 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-core/build.gradle.kts (renamed from simulator/opendc/opendc-compute/build.gradle.kts) | 14 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/Flavor.kt (renamed from simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/Flavor.kt) | 2 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/Server.kt (renamed from simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/Server.kt) | 16 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/ServerEvent.kt (renamed from simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/ServerEvent.kt) | 16 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/ServerState.kt (renamed from simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/ServerState.kt) | 2 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/image/EmptyImage.kt (renamed from simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/image/EmptyImage.kt) | 13 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/image/Image.kt (renamed from simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/image/Image.kt) | 19 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/metal/Metadata.kt (renamed from simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/metal/Metadata.kt) | 4 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/metal/Node.kt (renamed from simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/metal/Node.kt) | 14 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/metal/NodeEvent.kt (renamed from simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/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/opendc-compute/src/main/kotlin/com/atlarge/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/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/metal/driver/BareMetalDriver.kt) | 22 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/metal/service/ProvisioningService.kt (renamed from simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/metal/service/ProvisioningService.kt) | 16 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/metal/service/SimpleProvisioningService.kt (renamed from simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/metal/service/SimpleProvisioningService.kt) | 35 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/virt/Hypervisor.kt (renamed from simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/Hypervisor.kt) | 10 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/virt/HypervisorEvent.kt (renamed from simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/HypervisorEvent.kt) | 10 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/virt/driver/InsufficientMemoryOnServerException.kt (renamed from simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/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/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/driver/VirtDriver.kt) | 25 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/virt/service/VirtProvisioningEvent.kt (renamed from simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/VirtProvisioningEvent.kt) | 4 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/virt/service/VirtProvisioningService.kt (renamed from simulator/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/SimulationEngine.kt) | 45 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/workload/VmWorkload.kt | 47 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-simulator/build.gradle.kts (renamed from simulator/odcsim/odcsim-engine-omega/build.gradle.kts) | 23 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/ComputeSimExecutionContext.kt | 36 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/HypervisorView.kt | 37 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimBareMetalDriver.kt | 246 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimVirtDriver.kt | 206 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimVirtDriverWorkload.kt (renamed from simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/execution/ServerManagementContext.kt) | 30 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimVirtProvisioningService.kt | 393 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimWorkloadImage.kt (renamed from simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/OmegaSimulationEngineProvider.kt) | 30 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/AllocationPolicy.kt | 50 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/AvailableCoreMemoryAllocationPolicy.kt (renamed from simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/allocation/AvailableCoreMemoryAllocationPolicy.kt) | 10 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/AvailableMemoryAllocationPolicy.kt | 37 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/ComparableAllocationPolicyLogic.kt (renamed from simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/allocation/ComparableAllocationPolicyLogic.kt) | 19 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/NumberOfActiveServersAllocationPolicy.kt | 37 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/ProvisionedCoresAllocationPolicy.kt (renamed from simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/allocation/ProvisionedCoresAllocationPolicy.kt) | 10 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/RandomAllocationPolicy.kt (renamed from simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/allocation/RandomAllocationPolicy.kt) | 17 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/ReplayAllocationPolicy.kt | 56 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/power/PowerModel.kt (renamed from simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/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/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/metal/power/PowerModels.kt) | 9 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/power/Powerable.kt (renamed from simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/power/Powerable.kt) | 4 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimBareMetalDriverTest.kt (renamed from simulator/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/metal/driver/SimpleBareMetalDriverTest.kt) | 81 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimProvisioningServiceTest.kt (renamed from simulator/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/metal/service/SimpleProvisioningServiceTest.kt) | 63 | ||||
| -rw-r--r-- | simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimVirtDriverTest.kt | 145 | ||||
| -rw-r--r-- | simulator/opendc-core/build.gradle.kts (renamed from simulator/opendc/opendc-core/build.gradle.kts) | 9 | ||||
| -rw-r--r-- | simulator/opendc-core/src/main/kotlin/org/opendc/core/Environment.kt (renamed from simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/Environment.kt) | 8 | ||||
| -rw-r--r-- | simulator/opendc-core/src/main/kotlin/org/opendc/core/Identity.kt (renamed from simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/Identity.kt) | 14 | ||||
| -rw-r--r-- | simulator/opendc-core/src/main/kotlin/org/opendc/core/Platform.kt (renamed from simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/Platform.kt) | 10 | ||||
| -rw-r--r-- | simulator/opendc-core/src/main/kotlin/org/opendc/core/User.kt (renamed from simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/User.kt) | 8 | ||||
| -rw-r--r-- | simulator/opendc-core/src/main/kotlin/org/opendc/core/Zone.kt (renamed from simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/Zone.kt) | 12 | ||||
| -rw-r--r-- | simulator/opendc-core/src/main/kotlin/org/opendc/core/resource/Resource.kt (renamed from simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/resource/Resource.kt) | 8 | ||||
| -rw-r--r-- | simulator/opendc-core/src/main/kotlin/org/opendc/core/resource/TagContainer.kt (renamed from simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/resource/TagContainer.kt) | 10 | ||||
| -rw-r--r-- | simulator/opendc-core/src/main/kotlin/org/opendc/core/services/ServiceKey.kt (renamed from simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/services/ServiceKey.kt) | 14 | ||||
| -rw-r--r-- | simulator/opendc-core/src/main/kotlin/org/opendc/core/services/ServiceRegistry.kt (renamed from simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/services/ServiceRegistry.kt) | 6 | ||||
| -rw-r--r-- | simulator/opendc-core/src/main/kotlin/org/opendc/core/services/ServiceRegistryImpl.kt (renamed from simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/services/ServiceRegistryImpl.kt) | 9 | ||||
| -rw-r--r-- | simulator/opendc-core/src/main/kotlin/org/opendc/core/workload/Workload.kt (renamed from simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/workload/Workload.kt) | 14 | ||||
| -rw-r--r-- | simulator/opendc-experiments/build.gradle.kts (renamed from simulator/odcsim/build.gradle.kts) | 4 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc18/build.gradle.kts (renamed from simulator/opendc/opendc-experiments-sc18/build.gradle.kts) | 19 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc18/src/main/kotlin/org/opendc/experiments/sc18/TestExperiment.kt (renamed from simulator/opendc/opendc-experiments-sc18/src/main/kotlin/com/atlarge/opendc/experiments/sc18/TestExperiment.kt) | 74 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc18/src/main/resources/env/setup-test.json (renamed from simulator/opendc/opendc-experiments-sc18/src/main/resources/env/setup-test.json) | 0 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/build.gradle.kts (renamed from simulator/opendc/opendc-experiments-sc20/build.gradle.kts) | 16 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/Main.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/Main.kt) | 51 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/Experiment.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/experiment/Experiment.kt) | 32 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/ExperimentHelpers.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/experiment/ExperimentHelpers.kt) | 155 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/Portfolio.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/experiment/Portfolio.kt) | 20 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/Portfolios.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/experiment/Portfolios.kt) | 59 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/Run.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/experiment/Run.kt) | 63 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/Scenario.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/experiment/Scenario.kt) | 28 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/model/OperationalPhenomena.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/experiment/model/OperationalPhenomena.kt) | 2 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/model/Topology.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/experiment/model/Topology.kt) | 2 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/model/Workload.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/experiment/model/Workload.kt) | 16 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/monitor/ExperimentMonitor.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/experiment/monitor/ExperimentMonitor.kt) | 30 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/monitor/ParquetExperimentMonitor.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/experiment/monitor/ParquetExperimentMonitor.kt) | 26 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/reporter/ConsoleExperimentReporter.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/reporter/ConsoleExperimentReporter.kt) | 20 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/runner/ContainerExperimentDescriptor.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/runner/ContainerExperimentDescriptor.kt) | 10 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/runner/ExperimentDescriptor.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/runner/ExperimentDescriptor.kt) | 14 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/runner/ExperimentRunner.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/runner/ExperimentRunner.kt) | 12 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/runner/TrialExperimentDescriptor.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/runner/TrialExperimentDescriptor.kt) | 2 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/runner/execution/ExperimentExecutionContext.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/runner/execution/ExperimentExecutionContext.kt) | 2 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/runner/execution/ExperimentExecutionListener.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/runner/execution/ExperimentExecutionListener.kt) | 16 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/runner/execution/ExperimentExecutionResult.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/runner/execution/ExperimentExecutionResult.kt) | 2 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/runner/execution/ExperimentScheduler.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/runner/execution/ExperimentScheduler.kt) | 16 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/runner/execution/ThreadPoolExperimentScheduler.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/runner/execution/ThreadPoolExperimentScheduler.kt) | 19 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/runner/internal/DefaultExperimentRunner.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/runner/internal/DefaultExperimentRunner.kt) | 24 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/telemetry/Event.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/telemetry/Event.kt) | 4 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/telemetry/HostEvent.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/telemetry/HostEvent.kt) | 32 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/telemetry/ProvisionerEvent.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/telemetry/ProvisionerEvent.kt) | 18 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/telemetry/RunEvent.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/telemetry/RunEvent.kt) | 12 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/telemetry/VmEvent.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/telemetry/VmEvent.kt) | 28 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/telemetry/parquet/ParquetEventWriter.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/telemetry/parquet/ParquetEventWriter.kt) | 47 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/telemetry/parquet/ParquetHostEventWriter.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/telemetry/parquet/ParquetHostEventWriter.kt) | 18 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/telemetry/parquet/ParquetProvisionerEventWriter.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/telemetry/parquet/ParquetProvisionerEventWriter.kt) | 18 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/telemetry/parquet/ParquetRunEventWriter.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/telemetry/parquet/ParquetRunEventWriter.kt) | 18 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20ParquetTraceReader.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/trace/Sc20ParquetTraceReader.kt) | 32 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20RawParquetTraceReader.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/trace/Sc20RawParquetTraceReader.kt) | 45 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20StreamingParquetTraceReader.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/trace/Sc20StreamingParquetTraceReader.kt) | 88 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20TraceConverter.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/trace/Sc20TraceConverter.kt) | 82 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/WorkloadSampler.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/trace/WorkloadSampler.kt) | 36 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/main/resources/log4j2.xml (renamed from simulator/opendc/opendc-experiments-sc20/src/main/resources/log4j2.xml) | 11 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/test/kotlin/org/opendc/experiments/sc20/Sc20IntegrationTest.kt (renamed from simulator/opendc/opendc-experiments-sc20/src/test/kotlin/com/atlarge/opendc/experiments/sc20/Sc20IntegrationTest.kt) | 111 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/test/resources/env/single.txt (renamed from simulator/opendc/opendc-experiments-sc20/src/test/resources/env/single.txt) | 0 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/test/resources/env/topology.txt (renamed from simulator/opendc/opendc-experiments-sc20/src/test/resources/env/topology.txt) | 0 | ||||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/test/resources/trace/meta.parquet (renamed from simulator/opendc/opendc-experiments-sc20/src/test/resources/trace/meta.parquet) | bin | 2148 -> 2148 bytes | |||
| -rw-r--r-- | simulator/opendc-experiments/opendc-experiments-sc20/src/test/resources/trace/trace.parquet (renamed from simulator/opendc/opendc-experiments-sc20/src/test/resources/trace/trace.parquet) | bin | 1672463 -> 1672463 bytes | |||
| -rw-r--r-- | simulator/opendc-format/build.gradle.kts (renamed from simulator/opendc/opendc-format/build.gradle.kts) | 23 | ||||
| -rw-r--r-- | simulator/opendc-format/src/main/kotlin/org/opendc/format/environment/EnvironmentReader.kt (renamed from simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/environment/EnvironmentReader.kt) | 17 | ||||
| -rw-r--r-- | simulator/opendc-format/src/main/kotlin/org/opendc/format/environment/sc18/Model.kt (renamed from simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/environment/sc18/Model.kt) | 24 | ||||
| -rw-r--r-- | simulator/opendc-format/src/main/kotlin/org/opendc/format/environment/sc18/Sc18EnvironmentReader.kt (renamed from simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/environment/sc18/Sc18EnvironmentReader.kt) | 54 | ||||
| -rw-r--r-- | simulator/opendc-format/src/main/kotlin/org/opendc/format/environment/sc20/Model.kt (renamed from simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/environment/sc20/Model.kt) | 24 | ||||
| -rw-r--r-- | simulator/opendc-format/src/main/kotlin/org/opendc/format/environment/sc20/Sc20ClusterEnvironmentReader.kt (renamed from simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/environment/sc20/Sc20ClusterEnvironmentReader.kt) | 70 | ||||
| -rw-r--r-- | simulator/opendc-format/src/main/kotlin/org/opendc/format/environment/sc20/Sc20EnvironmentReader.kt (renamed from simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/environment/sc20/Sc20EnvironmentReader.kt) | 54 | ||||
| -rw-r--r-- | simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/PerformanceInterferenceModelReader.kt (renamed from simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/PerformanceInterferenceModelReader.kt) | 12 | ||||
| -rw-r--r-- | simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/TraceEntry.kt (renamed from simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/TraceEntry.kt) | 14 | ||||
| -rw-r--r-- | simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/TraceReader.kt (renamed from simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/TraceReader.kt) | 10 | ||||
| -rw-r--r-- | simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/TraceWriter.kt (renamed from simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/TraceWriter.kt) | 8 | ||||
| -rw-r--r-- | simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/VmPlacementReader.kt (renamed from simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/VmPlacementReader.kt) | 6 | ||||
| -rw-r--r-- | simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/bitbrains/BitbrainsTraceReader.kt (renamed from simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/bitbrains/BitbrainsTraceReader.kt) | 65 | ||||
| -rw-r--r-- | simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/gwf/GwfTraceReader.kt (renamed from simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/gwf/GwfTraceReader.kt) | 59 | ||||
| -rw-r--r-- | simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/sc20/PerformanceInterferenceEntry.kt (renamed from simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/sc20/PerformanceInterferenceEntry.kt) | 2 | ||||
| -rw-r--r-- | simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/sc20/Sc20PerformanceInterferenceReader.kt (renamed from simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/sc20/Sc20PerformanceInterferenceReader.kt) | 21 | ||||
| -rw-r--r-- | simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/sc20/Sc20TraceReader.kt (renamed from simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/sc20/Sc20TraceReader.kt) | 51 | ||||
| -rw-r--r-- | simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/sc20/Sc20VmPlacementReader.kt (renamed from simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/sc20/Sc20VmPlacementReader.kt) | 10 | ||||
| -rw-r--r-- | simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/swf/SwfTraceReader.kt (renamed from simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/swf/SwfTraceReader.kt) | 87 | ||||
| -rw-r--r-- | simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/wtf/WtfTraceReader.kt | 128 | ||||
| -rw-r--r-- | simulator/opendc-format/src/test/kotlin/org/opendc/format/trace/swf/SwfTraceReaderTest.kt | 47 | ||||
| -rw-r--r-- | simulator/opendc-format/src/test/kotlin/org/opendc/format/trace/wtf/WtfTraceReaderTest.kt | 46 | ||||
| -rw-r--r-- | simulator/opendc-format/src/test/resources/swf_trace.txt (renamed from simulator/opendc/opendc-format/src/test/resources/swf_trace.txt) | 0 | ||||
| -rw-r--r-- | simulator/opendc-format/src/test/resources/wtf-trace/tasks/schema-1.0/part.0.parquet | bin | 0 -> 87475 bytes | |||
| -rw-r--r-- | simulator/opendc-runner-web/build.gradle.kts (renamed from simulator/opendc/opendc-runner-web/build.gradle.kts) | 17 | ||||
| -rw-r--r-- | simulator/opendc-runner-web/src/main/kotlin/org/opendc/runner/web/Main.kt (renamed from simulator/opendc/opendc-runner-web/src/main/kotlin/com/atlarge/opendc/runner/web/Main.kt) | 91 | ||||
| -rw-r--r-- | simulator/opendc-runner-web/src/main/kotlin/org/opendc/runner/web/ResultProcessor.kt (renamed from simulator/opendc/opendc-runner-web/src/main/kotlin/com/atlarge/opendc/runner/web/ResultProcessor.kt) | 92 | ||||
| -rw-r--r-- | simulator/opendc-runner-web/src/main/kotlin/org/opendc/runner/web/ScenarioManager.kt (renamed from simulator/opendc/opendc-runner-web/src/main/kotlin/com/atlarge/opendc/runner/web/ScenarioManager.kt) | 38 | ||||
| -rw-r--r-- | simulator/opendc-runner-web/src/main/kotlin/org/opendc/runner/web/TopologyParser.kt (renamed from simulator/opendc/opendc-runner-web/src/main/kotlin/com/atlarge/opendc/runner/web/TopologyParser.kt) | 79 | ||||
| -rw-r--r-- | simulator/opendc-runner-web/src/main/resources/log4j2.xml (renamed from simulator/opendc/opendc-runner-web/src/main/resources/log4j2.xml) | 9 | ||||
| -rw-r--r-- | simulator/opendc-simulator/build.gradle.kts | 0 | ||||
| -rw-r--r-- | simulator/opendc-simulator/opendc-simulator-compute/build.gradle.kts (renamed from simulator/odcsim/odcsim-api/build.gradle.kts) | 11 | ||||
| -rw-r--r-- | simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimBareMetalMachine.kt | 281 | ||||
| -rw-r--r-- | simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimExecutionContext.kt (renamed from simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/execution/ServerContext.kt) | 38 | ||||
| -rw-r--r-- | simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimHypervisor.kt (renamed from simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/driver/SimpleVirtDriver.kt) | 430 | ||||
| -rw-r--r-- | simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachine.kt | 48 | ||||
| -rw-r--r-- | simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachineModel.kt | 34 | ||||
| -rw-r--r-- | simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/interference/PerformanceInterferenceModel.kt | 134 | ||||
| -rw-r--r-- | simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/MemoryUnit.kt (renamed from simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/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/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/ProcessingNode.kt) | 16 | ||||
| -rw-r--r-- | simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/ProcessingUnit.kt (renamed from simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/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/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/image/FlopsApplicationImage.kt) | 30 | ||||
| -rw-r--r-- | simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkload.kt (renamed from simulator/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/SimulationContext.kt) | 54 | ||||
| -rw-r--r-- | simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimWorkload.kt | 41 | ||||
| -rw-r--r-- | simulator/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimHypervisorTest.kt | 129 | ||||
| -rw-r--r-- | simulator/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimMachineTest.kt | 83 | ||||
| -rw-r--r-- | simulator/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimFlopsWorkloadTest.kt (renamed from simulator/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/core/image/FlopsApplicationImageTest.kt) | 37 | ||||
| -rw-r--r-- | simulator/opendc-simulator/opendc-simulator-core/build.gradle.kts | 32 | ||||
| -rw-r--r-- | simulator/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/utils/DelayControllerClockAdapter.kt | 46 | ||||
| -rw-r--r-- | simulator/opendc-simulator/opendc-simulator-failures/build.gradle.kts | 31 | ||||
| -rw-r--r-- | simulator/opendc-simulator/opendc-simulator-failures/src/main/kotlin/org/opendc/simulator/failures/CorrelatedFaultInjector.kt (renamed from simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/failure/CorrelatedFaultInjector.kt) | 25 | ||||
| -rw-r--r-- | simulator/opendc-simulator/opendc-simulator-failures/src/main/kotlin/org/opendc/simulator/failures/FailureDomain.kt (renamed from simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/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/opendc-core/src/main/kotlin/com/atlarge/opendc/core/failure/FaultInjector.kt) | 6 | ||||
| -rw-r--r-- | simulator/opendc-simulator/opendc-simulator-failures/src/main/kotlin/org/opendc/simulator/failures/UncorrelatedFaultInjector.kt (renamed from simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/failure/UncorrelatedFaultInjector.kt) | 21 | ||||
| -rw-r--r-- | simulator/opendc-utils/build.gradle.kts | 32 | ||||
| -rw-r--r-- | simulator/opendc-utils/src/main/kotlin/org/opendc/utils/flow/EventFlow.kt (renamed from simulator/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/flow/EventFlow.kt) | 9 | ||||
| -rw-r--r-- | simulator/opendc-utils/src/main/kotlin/org/opendc/utils/flow/StateFlow.kt (renamed from simulator/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/flow/StateFlow.kt) | 6 | ||||
| -rw-r--r-- | simulator/opendc-workflows/build.gradle.kts (renamed from simulator/opendc/opendc-workflows/build.gradle.kts) | 18 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/JobState.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/JobState.kt) | 14 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/StageWorkflowSchedulerListener.kt | 37 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/StageWorkflowService.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/StageWorkflowService.kt) | 86 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/TaskState.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/TaskState.kt) | 26 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/TaskStatus.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/TaskStatus.kt) | 2 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/WorkflowEvent.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/WorkflowEvent.kt) | 10 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/WorkflowSchedulerMode.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/WorkflowSchedulerMode.kt) | 29 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/WorkflowService.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/WorkflowService.kt) | 14 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/StagePolicy.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/StagePolicy.kt) | 12 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/job/DurationJobOrderPolicy.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/job/DurationJobOrderPolicy.kt) | 22 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/job/JobAdmissionPolicy.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/job/JobAdmissionPolicy.kt) | 18 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/job/JobOrderPolicy.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/job/JobOrderPolicy.kt) | 12 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/job/LimitJobAdmissionPolicy.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/job/LimitJobAdmissionPolicy.kt) | 14 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/job/LoadJobAdmissionPolicy.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/job/LoadJobAdmissionPolicy.kt) | 14 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/job/NullJobAdmissionPolicy.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/job/NullJobAdmissionPolicy.kt) | 14 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/job/RandomJobOrderPolicy.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/job/RandomJobOrderPolicy.kt) | 21 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/job/SizeJobOrderPolicy.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/job/SizeJobOrderPolicy.kt) | 16 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/job/SubmissionTimeJobOrderPolicy.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/job/SubmissionTimeJobOrderPolicy.kt) | 16 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/FirstFitResourceSelectionPolicy.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/resource/FirstFitResourceSelectionPolicy.kt) | 17 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/FunctionalResourceFilterPolicy.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/resource/FunctionalResourceFilterPolicy.kt) | 14 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/RandomResourceSelectionPolicy.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/resource/RandomResourceSelectionPolicy.kt) | 16 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/ResourceFilterPolicy.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/resource/ResourceFilterPolicy.kt) | 18 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/ResourceSelectionPolicy.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/resource/ResourceSelectionPolicy.kt) | 12 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/ActiveTaskOrderPolicy.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/ActiveTaskOrderPolicy.kt) | 16 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/BalancingTaskEligibilityPolicy.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/BalancingTaskEligibilityPolicy.kt) | 16 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/CompletionTaskOrderPolicy.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/CompletionTaskOrderPolicy.kt) | 16 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/DependenciesTaskOrderPolicy.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/DependenciesTaskOrderPolicy.kt) | 14 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/DependentsTaskOrderPolicy.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/DependentsTaskOrderPolicy.kt) | 14 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/DurationHistoryTaskOrderPolicy.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/DurationHistoryTaskOrderPolicy.kt) | 17 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/DurationTaskOrderPolicy.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/DurationTaskOrderPolicy.kt) | 22 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/LimitPerJobTaskEligibilityPolicy.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/LimitPerJobTaskEligibilityPolicy.kt) | 16 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/LimitTaskEligibilityPolicy.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/LimitTaskEligibilityPolicy.kt) | 14 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/LoadTaskEligibilityPolicy.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/LoadTaskEligibilityPolicy.kt) | 14 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/NullTaskEligibilityPolicy.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/NullTaskEligibilityPolicy.kt) | 12 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/RandomTaskEligibilityPolicy.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/RandomTaskEligibilityPolicy.kt) | 16 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/RandomTaskOrderPolicy.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/RandomTaskOrderPolicy.kt) | 12 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/SubmissionTimeTaskOrderPolicy.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/SubmissionTimeTaskOrderPolicy.kt) | 10 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/TaskEligibilityPolicy.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/TaskEligibilityPolicy.kt) | 14 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/TaskOrderPolicy.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/TaskOrderPolicy.kt) | 8 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/workload/Job.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/workload/Job.kt) | 18 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/workload/Metadata.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/workload/Metadata.kt) | 4 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/workload/Task.kt (renamed from simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/workload/Task.kt) | 16 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/test/kotlin/org/opendc/workflows/service/StageWorkflowSchedulerIntegrationTest.kt (renamed from simulator/opendc/opendc-workflows/src/test/kotlin/com/atlarge/opendc/workflows/service/StageWorkflowSchedulerIntegrationTest.kt) | 58 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/test/resources/environment.json (renamed from simulator/opendc/opendc-workflows/src/test/resources/environment.json) | 0 | ||||
| -rw-r--r-- | simulator/opendc-workflows/src/test/resources/trace.gwf (renamed from simulator/opendc/opendc-workflows/src/test/resources/trace.gwf) | 0 | ||||
| -rw-r--r-- | simulator/opendc/README.md | 8 | ||||
| -rw-r--r-- | simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/execution/ShutdownException.kt | 53 | ||||
| -rw-r--r-- | simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/image/FlopsHistoryFragment.kt | 3 | ||||
| -rw-r--r-- | simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/image/VmImage.kt | 34 | ||||
| -rw-r--r-- | simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/workload/PerformanceInterferenceModel.kt | 123 | ||||
| -rw-r--r-- | simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/workload/VmWorkload.kt | 25 | ||||
| -rw-r--r-- | simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/metal/driver/SimpleBareMetalDriver.kt | 478 | ||||
| -rw-r--r-- | simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/HypervisorImage.kt | 57 | ||||
| -rw-r--r-- | simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/HypervisorView.kt | 15 | ||||
| -rw-r--r-- | simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/SimpleVirtProvisioningService.kt | 351 | ||||
| -rw-r--r-- | simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/VirtProvisioningService.kt | 42 | ||||
| -rw-r--r-- | simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/allocation/AllocationPolicy.kt | 25 | ||||
| -rw-r--r-- | simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/allocation/AvailableMemoryAllocationPolicy.kt | 15 | ||||
| -rw-r--r-- | simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/allocation/NumberOfActiveServersAllocationPolicy.kt | 15 | ||||
| -rw-r--r-- | simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/allocation/ReplayAllocationPolicy.kt | 34 | ||||
| -rw-r--r-- | simulator/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/virt/HypervisorTest.kt | 167 | ||||
| -rw-r--r-- | simulator/opendc/opendc-format/src/test/kotlin/com/atlarge/opendc/format/trace/swf/SwfTraceReaderTest.kt | 23 | ||||
| -rw-r--r-- | simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/StageWorkflowSchedulerListener.kt | 39 | ||||
| -rw-r--r-- | simulator/settings.gradle.kts | 25 |
244 files changed, 4650 insertions, 5322 deletions
diff --git a/simulator/Dockerfile b/simulator/Dockerfile index e42c7f14..880af95d 100644 --- a/simulator/Dockerfile +++ b/simulator/Dockerfile @@ -23,9 +23,9 @@ RUN ./gradlew clean build --no-daemon > /dev/null 2>&1 || true # Build project COPY ./ /app/ -RUN ./gradlew --no-daemon :opendc:opendc-runner-web:installDist +RUN ./gradlew --no-daemon :opendc-runner-web:installDist FROM openjdk:14-slim -COPY --from=builder /app/opendc/opendc-runner-web/build/install /app +COPY --from=builder /app/opendc-runner-web/build/install /app WORKDIR /app CMD opendc-runner-web/bin/opendc-runner-web diff --git a/simulator/README.md b/simulator/README.md index 0e9a1671..61ef1d43 100644 --- a/simulator/README.md +++ b/simulator/README.md @@ -8,22 +8,34 @@ <p align="center"> Collaborative Datacenter Simulation and Exploration for Everybody </p> -<p align="center"> - <a href="https://travis-ci.org/atlarge-research/opendc-simulator"> - <img src="https://travis-ci.org/atlarge-research/opendc-simulator.svg?branch=master" alt="Build Status"> - </a> +<p align="center"> <a href="https://opensource.org/licenses/MIT"> - <img src="https://img.shields.io/badge/License-MIT-yellow.svg" alt="MIT License"> + <img src="https://img.shields.io/badge/License-MIT-green.svg" alt="MIT License"> </a> </p> ## Introduction -This repository hosts the source code and development of the simulation component of the [OpenDC](https://opendc.org) project. This component is responsible for modelling and simulation of datacenters and their components. We have structured the repository into two individual subprojects: -- **[odcsim](/odcsim)** - A framework for discrete event simulation using the [Kotlin](https://kotlinlang.org/) language. -- **[opendc](/opendc)** - A collection of models for simulating clouds, datacenters and their components using the **odcsim** framework. - +This directory hosts the source code and development of the simulation component of the [OpenDC](https://opendc.org) project. +This component is responsible for modelling and simulation of datacenters and their components. We have structured the directory into several subprojects: +- **[opendc-core](opendc-core)** + This module establishes core concepts and terminology of datacenters that we share across the various modules. + Other `opendc` modules build on these concepts and extend it in various directions (e.g. virtual machines or workflows). +- **[opendc-compute](opendc-compute)** + The [Infrastructure as a Service](https://en.wikipedia.org/wiki/Infrastructure_as_a_Service) (IaaS) component of OpenDC for computing infrastructure (similar to + [Amazon EC2](https://aws.amazon.com/ec2/) and [Google Compute Engine](https://cloud.google.com/compute)). +- **[opendc-workflows](opendc-workflows)** + Workflow orchestration service built on top of OpenDC. +- **[opendc-format](opendc-format)** + Collection of libraries for processing data formats related to (simulation of) cloud computing and datacenters. +- **[opendc-experiments](opendc-experiments)** + Collection of experiments that use OpenDC to explore various concepts of cloud computing and datacenters. +- **[opendc-runner-web](opendc-runner-web)** + Experiment runner that integrates with the OpenDC web interface. +- **[opendc-simulator](opendc-simulator)** + Collection of libraries that enable simulation of various components of datacenters. +- **[opendc-utils](opendc-utils)** + Collection of utilities that are shared across the OpenDC subprojects. + ## Documentation Check out the [Getting Started](#getting-started) section for a quick overview. diff --git a/simulator/build.gradle.kts b/simulator/build.gradle.kts index 4775369b..b104654b 100644 --- a/simulator/build.gradle.kts +++ b/simulator/build.gradle.kts @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2017 atlarge-research + * Copyright (c) 2017 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 @@ -27,6 +25,6 @@ plugins { } allprojects { - group = "com.atlarge.opendc" + group = "org.opendc" version = "2.0.0" } diff --git a/simulator/buildSrc/build.gradle.kts b/simulator/buildSrc/build.gradle.kts index 6ed95c71..7ccd920f 100644 --- a/simulator/buildSrc/build.gradle.kts +++ b/simulator/buildSrc/build.gradle.kts @@ -40,7 +40,7 @@ repositories { } dependencies { - implementation(kotlin("gradle-plugin", version = "1.3.70")) - implementation("org.jlleitschuh.gradle:ktlint-gradle:9.2.1") + implementation(kotlin("gradle-plugin", version = "1.4.10")) + implementation("org.jlleitschuh.gradle:ktlint-gradle:9.4.0") implementation("org.jetbrains.dokka:dokka-gradle-plugin:0.10.1") } diff --git a/simulator/buildSrc/src/main/kotlin/kotlin-library-convention.gradle.kts b/simulator/buildSrc/src/main/kotlin/kotlin-library-convention.gradle.kts index c0c37a09..452db573 100644 --- a/simulator/buildSrc/src/main/kotlin/kotlin-library-convention.gradle.kts +++ b/simulator/buildSrc/src/main/kotlin/kotlin-library-convention.gradle.kts @@ -40,6 +40,10 @@ java { sourceCompatibility = JavaVersion.VERSION_1_8 } +kotlin { + explicitApi() +} + tasks.withType<KotlinCompile>().configureEach { kotlinOptions.jvmTarget = "1.8" kotlinOptions.freeCompilerArgs += "-Xopt-in=kotlin.RequiresOptIn" @@ -56,7 +60,3 @@ tasks.jacocoTestReport { html.isEnabled = true } } - -dependencies { - implementation(kotlin("stdlib")) -} diff --git a/simulator/buildSrc/src/main/kotlin/library.kt b/simulator/buildSrc/src/main/kotlin/library.kt index 1a3c30a6..af278a07 100644 --- a/simulator/buildSrc/src/main/kotlin/library.kt +++ b/simulator/buildSrc/src/main/kotlin/library.kt @@ -45,5 +45,5 @@ object Library { /** * Kotlin coroutines support */ - val KOTLINX_COROUTINES = "1.3.7" + val KOTLINX_COROUTINES = "1.3.9" } diff --git a/simulator/gradle/wrapper/gradle-wrapper.jar b/simulator/gradle/wrapper/gradle-wrapper.jar Binary files differindex 62d4c053..e708b1c0 100644 --- a/simulator/gradle/wrapper/gradle-wrapper.jar +++ b/simulator/gradle/wrapper/gradle-wrapper.jar diff --git a/simulator/gradle/wrapper/gradle-wrapper.properties b/simulator/gradle/wrapper/gradle-wrapper.properties index bb8b2fc2..12d38de6 100644 --- a/simulator/gradle/wrapper/gradle-wrapper.properties +++ b/simulator/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.6.1-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/simulator/gradlew b/simulator/gradlew index fbd7c515..4f906e0c 100755 --- a/simulator/gradlew +++ b/simulator/gradlew @@ -130,7 +130,7 @@ fi if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath diff --git a/simulator/gradlew.bat b/simulator/gradlew.bat index 5093609d..107acd32 100644 --- a/simulator/gradlew.bat +++ b/simulator/gradlew.bat @@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -54,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -64,21 +64,6 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line @@ -86,7 +71,7 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell diff --git a/simulator/odcsim/README.md b/simulator/odcsim/README.md deleted file mode 100644 index 78cfaa27..00000000 --- a/simulator/odcsim/README.md +++ /dev/null @@ -1,54 +0,0 @@ -<h1 align="center"> - <a href="http://opendc.org/"> - <img src="../misc/artwork/logo.png" width="100" alt="OpenDC"> - </a> - <br> - odcsim -</h1> - -## Introduction -**odcsim** is a framework for discrete event simulation in Kotlin, used -by the [OpenDC](https://opendc.org) project. -Projects are defined in terms of a hierarchical grouping of actors -and the interactions between these actors -([Actor model](https://en.wikipedia.org/wiki/Actor_model)). - -## Getting Started - -The instructions below are meant for when you would like to use `odcsim` separately from `opendc`. If you simply want to use the simulator, you do not need to follow them, please refer to the [main README](../README.md) for instructions. - -### Installation -Please add the required packages as dependency in your project. -Releases are available in the [Maven Central Repository](https://search.maven.org/). - -The package `odcsim-core` is required to construct a simulation model. -A `odcsim-engine-*` package is needed for running the simulation -model. - -#### Gradle -Groovy -```groovy -implementation 'com.atlarge.odcsim:odcsim-api:2.0.0' -runtime 'com.atlarge.odcsim:odcsim-engine-omega:2.0.0' -``` -Kotlin -```groovy -implementation("com.atlarge.odcsim:odcsim-api:2.0.0") -runtime("com.atlarge.odcsim:odcsim-engine-omega:2.0.0") -``` - -#### Maven -```xml -<dependency> - <groupId>com.atlarge.odcsim</groupId> - <artifactId>odcsim-api</artifactId> - <version>2.0.0</version> -</dependency> - -<dependency> - <groupId>com.atlarge.odcsim</groupId> - <artifactId>odcsim-engine-omega</artifactId> - <version>2.0.0</version> -</dependency> -``` - diff --git a/simulator/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/Domain.kt b/simulator/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/Domain.kt deleted file mode 100644 index c850952c..00000000 --- a/simulator/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/Domain.kt +++ /dev/null @@ -1,54 +0,0 @@ -/* - * MIT License - * - * 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 com.atlarge.odcsim - -import kotlinx.coroutines.CoroutineScope - -/** - * An isolated execution unit that runs concurrently in simulation to the other simulation domains. A domain defines a - * logical boundary between processes in simulation. - */ -public interface Domain : CoroutineScope { - /** - * The name of this domain. - */ - public val name: String - - /** - * The parent domain to which the lifecycle of this domain is bound. In case this is a root domain, this refers to - * itself. - */ - public val parent: Domain - - /** - * Construct an anonymous simulation sub-domain that is bound to the lifecycle of this domain. - */ - public fun newDomain(): Domain - - /** - * Construct a new simulation sub-domain with the specified [name]. - */ - public fun newDomain(name: String): Domain -} diff --git a/simulator/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/SimulationEngineProvider.kt b/simulator/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/SimulationEngineProvider.kt deleted file mode 100644 index a975fa3c..00000000 --- a/simulator/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/SimulationEngineProvider.kt +++ /dev/null @@ -1,35 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 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 com.atlarge.odcsim - -/** - * A factory for [SimulationEngine] instances that allows users to dynamically load engine implementations. - */ -public interface SimulationEngineProvider { - /** - * Construct an [SimulationEngine] with the given [name]. - */ - public operator fun invoke(name: String): SimulationEngine -} diff --git a/simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/OmegaSimulationEngine.kt b/simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/OmegaSimulationEngine.kt deleted file mode 100644 index e675b877..00000000 --- a/simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/OmegaSimulationEngine.kt +++ /dev/null @@ -1,264 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2018 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 com.atlarge.odcsim.engine.omega - -import com.atlarge.odcsim.Domain -import com.atlarge.odcsim.SimulationContext -import com.atlarge.odcsim.SimulationEngine -import com.atlarge.odcsim.engine.omega.logging.LoggerImpl -import java.time.Clock -import java.time.Instant -import java.time.ZoneId -import java.util.PriorityQueue -import java.util.UUID -import kotlin.coroutines.CoroutineContext -import kotlin.coroutines.coroutineContext -import kotlinx.coroutines.CancellableContinuation -import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.CoroutineExceptionHandler -import kotlinx.coroutines.CoroutineName -import kotlinx.coroutines.Delay -import kotlinx.coroutines.DisposableHandle -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.InternalCoroutinesApi -import kotlinx.coroutines.Job -import kotlinx.coroutines.Runnable -import kotlinx.coroutines.SupervisorJob -import org.jetbrains.annotations.Async -import org.slf4j.Logger - -/** - * The reference implementation of the [SimulationEngine] instance for the OpenDC simulation core. - * - * This engine implementation is a single-threaded implementation, running logical processes synchronously and - * provides a single priority queue for all events (messages, ticks, etc) that occur. - * - * @param name The name of the engine instance. - */ -public class OmegaSimulationEngine(override val name: String) : SimulationEngine { - /** - * The state of the actor system. - */ - private var state: SimulationEngineState = SimulationEngineState.CREATED - - /** - * The clock tracking the simulation time. - */ - private val clock: VirtualClock = VirtualClock(0) - - /** - * The event queue to process - */ - private val queue: PriorityQueue<Event> = PriorityQueue(Comparator<Event> { lhs, rhs -> - // Note that Comparator gives better performance than Comparable according to - // profiling - val cmp = lhs.time.compareTo(rhs.time) - if (cmp == 0) lhs.id.compareTo(rhs.id) else cmp - }) - - /** - * The active processes in the simulation engine. - */ - private val registry: MutableMap<String, Domain> = HashMap() - - /** - * A unique increasing identifier assigned to each event, needed because otherwise two events occurring in sequence - * (but at the same time) may be differently ordered in the internal priority queue (queue) since it does not - * guarantee insertion order. - */ - private var nextId: Long = 0 - - override fun newDomain(): Domain = newDomain(null) - - override fun newDomain(name: String): Domain = newDomain(name, null) - - override suspend fun run() { - check(state != SimulationEngineState.TERMINATED) { "The simulation engine is terminated" } - - if (state == SimulationEngineState.CREATED) { - state = SimulationEngineState.STARTED - } - - val job = coroutineContext[Job] - - while (job?.isActive == true) { - val event = queue.peek() ?: break - val delivery = event.time - - // A message should never be delivered out of order in this single-threaded implementation. Assert for - // sanity - assert(delivery >= clock.time) { "Message delivered out of order [expected=$delivery, actual=${clock.time}]" } - - clock.time = delivery - queue.poll() - - process(event) - } - } - - override suspend fun terminate() { - state = SimulationEngineState.TERMINATED - } - - /** - * Schedule the specified event to be processed by the engine. - */ - private fun schedule(@Async.Schedule event: Event) { - assert(event.time >= clock.time) { "Message scheduled in the past [received=${event.time}, actual=${clock.time}]" } - queue.add(event) - } - - /** - * Process the delivery of an event. - */ - @OptIn(ExperimentalCoroutinesApi::class) - private fun process(@Async.Execute event: Event) { - // This has been inlined into this method for performance - when (event) { - is Event.Dispatch -> - event.block.run() - is Event.Resume -> - with(event.continuation) { event.dispatcher.resumeUndispatched(Unit) } - is Event.Timeout -> - if (!event.isCancelled) - event.block.run() - } - } - - /** - * Spawn a new simulation domain. - */ - private fun newDomainImpl(name: String, parent: DomainImpl?): Domain { - val domain = DomainImpl(name, parent) - require(domain.path !in registry) { "Domain name $name not unique" } - registry[domain.path] = domain - return domain - } - - private fun newDomain(parent: DomainImpl?): Domain { - val name = "$" + UUID.randomUUID() - return newDomainImpl(name, parent) - } - - private fun newDomain(name: String, parent: DomainImpl?): Domain { - require(name.isNotEmpty()) { "Domain name may not be empty" } - require(!name.startsWith("$")) { "Domain name may not start with $-sign" } - require(!name.contains("/")) { "Domain name may not contain /" } - return newDomainImpl(name, parent) - } - - private inner class DomainImpl(override val name: String, parent: DomainImpl?) : SimulationContext, Domain { - val job: Job = SupervisorJob(parent?.job) - val path: String = (parent?.path ?: "") + "/$name" - - @InternalCoroutinesApi - private val dispatcher = object : CoroutineDispatcher(), Delay { - // CoroutineDispatcher - override fun dispatch(context: CoroutineContext, block: Runnable) { - schedule(Event.Dispatch(clock.time, nextId++, block)) - } - - // Delay - override fun scheduleResumeAfterDelay(timeMillis: Long, continuation: CancellableContinuation<Unit>) { - schedule(Event.Resume(clock.time + timeMillis, nextId++, this, continuation)) - } - - override fun invokeOnTimeout(timeMillis: Long, block: Runnable): DisposableHandle { - val event = Event.Timeout(clock.time + timeMillis, nextId++, block) - schedule(event) - return event - } - } - - private val exceptionHandler = CoroutineExceptionHandler { _, exception -> - log.error("Uncaught exception", exception) - } - - // SimulationContext - override val key: CoroutineContext.Key<*> = SimulationContext.Key - - override val domain: Domain = this - - override val clock: VirtualClock - get() = this@OmegaSimulationEngine.clock - - override val log: Logger by lazy(LazyThreadSafetyMode.NONE) { LoggerImpl.invoke(this) } - - override fun newDomain(): Domain = this@OmegaSimulationEngine.newDomain(this) - - override fun newDomain(name: String): Domain = this@OmegaSimulationEngine.newDomain(name, this) - - // Domain - override val parent: Domain = parent ?: this - - @InternalCoroutinesApi - override val coroutineContext: CoroutineContext = this + CoroutineName(name) + dispatcher + job + exceptionHandler - - override fun toString(): String = path - } - - /** - * Enumeration to track the state of the actor system. - */ - private enum class SimulationEngineState { - CREATED, STARTED, TERMINATED - } - - /** - * A wrapper around a message that has been scheduled for processing. - * - * @property time The point in time to deliver the message. - */ - private sealed class Event(val time: Long, val id: Long) { - class Dispatch(time: Long, id: Long, val block: Runnable) : Event(time, id) { - override fun toString(): String = "Dispatch[$time]" - } - - class Resume(time: Long, id: Long, val dispatcher: CoroutineDispatcher, val continuation: CancellableContinuation<Unit>) : Event(time, id) { - override fun toString(): String = "Resume[$time]" - } - - class Timeout(time: Long, id: Long, val block: Runnable, var isCancelled: Boolean = false) : Event(time, id), DisposableHandle { - override fun dispose() { - isCancelled = true - } - - override fun toString(): String = "Timeout[$time]" - } - } - - /** - * A virtual [Clock] implementation for keeping track of simulation time. - */ - private data class VirtualClock(var time: Long) : Clock() { - override fun withZone(zone: ZoneId?): Clock = throw NotImplementedError() - - override fun getZone(): ZoneId = ZoneId.systemDefault() - - override fun instant(): Instant = Instant.ofEpochMilli(time) - - override fun millis(): Long = time - } -} diff --git a/simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/logging/LocationAwareLoggerImpl.kt b/simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/logging/LocationAwareLoggerImpl.kt deleted file mode 100644 index fca4826e..00000000 --- a/simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/logging/LocationAwareLoggerImpl.kt +++ /dev/null @@ -1,567 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2019 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 com.atlarge.odcsim.engine.omega.logging - -import com.atlarge.odcsim.SimulationContext -import org.slf4j.Logger -import org.slf4j.Marker -import org.slf4j.helpers.MessageFormatter -import org.slf4j.spi.LocationAwareLogger - -/** - * An actor-specific [Logger] implementation that is aware of the calling location. - * - * @param ctx The owning [SimulationContext] of this logger. - * @param delegate The [LocationAwareLogger] to delegate the messages to. - */ -internal class LocationAwareLoggerImpl( - ctx: SimulationContext, - private val delegate: LocationAwareLogger -) : LoggerImpl(ctx), Logger by delegate { - /** - * The fully qualified name of this class. - */ - private val fqcn = LocationAwareLoggerImpl::class.java.name - - override fun trace(format: String?, arg: Any?) { - if (!delegate.isTraceEnabled) { - return - } - - withMdc { - val formattedMessage = MessageFormatter.format(format, arg).message - delegate.log(null, fqcn, LocationAwareLogger.TRACE_INT, formattedMessage, arrayOf(arg), null) - } - } - - override fun trace(format: String?, arg1: Any?, arg2: Any?) { - if (!delegate.isTraceEnabled) { - return - } - - withMdc { - val formattedMessage = MessageFormatter.format(format, arg1, arg2).message - delegate.log(null, fqcn, LocationAwareLogger.TRACE_INT, formattedMessage, arrayOf(arg1, arg2), null) - } - } - - override fun trace(format: String?, argArray: Array<Any?>) { - if (!delegate.isTraceEnabled) { - return - } - - withMdc { - val formattedMessage = MessageFormatter.arrayFormat(format, argArray).message - delegate.log(null, fqcn, LocationAwareLogger.TRACE_INT, formattedMessage, argArray, null) - } - } - - override fun trace(msg: String?, t: Throwable?) { - if (!delegate.isTraceEnabled) { - return - } - - withMdc { - delegate.log(null, fqcn, LocationAwareLogger.TRACE_INT, msg, null, t) - } - } - - override fun trace(marker: Marker?, msg: String?) { - if (!delegate.isTraceEnabled) { - return - } - - withMdc { - delegate.log(marker, fqcn, LocationAwareLogger.TRACE_INT, msg, null, null) - } - } - - override fun trace(marker: Marker?, format: String?, arg: Any?) { - if (!delegate.isTraceEnabled) { - return - } - - withMdc { - val formattedMessage = MessageFormatter.format(format, arg).message - delegate.log(marker, fqcn, LocationAwareLogger.TRACE_INT, formattedMessage, arrayOf(arg), null) - } - } - - override fun trace(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) { - if (!delegate.isTraceEnabled) { - return - } - - withMdc { - val formattedMessage = MessageFormatter.format(format, arg1, arg2).message - delegate.log(marker, fqcn, LocationAwareLogger.TRACE_INT, formattedMessage, arrayOf(arg1, arg2), null) - } - } - - override fun trace(marker: Marker?, format: String?, argArray: Array<Any?>) { - if (!delegate.isTraceEnabled) { - return - } - - withMdc { - val formattedMessage = MessageFormatter.arrayFormat(format, argArray).message - delegate.log(marker, fqcn, LocationAwareLogger.TRACE_INT, formattedMessage, argArray, null) - } - } - - override fun trace(marker: Marker?, msg: String?, t: Throwable?) { - if (!delegate.isTraceEnabled) { - return - } - - withMdc { - delegate.log(marker, fqcn, LocationAwareLogger.TRACE_INT, msg, null, t) - } - } - - override fun debug(msg: String?) { - if (!delegate.isDebugEnabled) { - return - } - - withMdc { - delegate.log(null, fqcn, LocationAwareLogger.DEBUG_INT, msg, null, null) - } - } - - override fun debug(format: String?, arg: Any?) { - if (!delegate.isDebugEnabled) { - return - } - - withMdc { - val formattedMessage = MessageFormatter.format(format, arg).message - delegate.log(null, fqcn, LocationAwareLogger.DEBUG_INT, formattedMessage, arrayOf(arg), null) - } - } - - override fun debug(format: String?, arg1: Any?, arg2: Any?) { - if (!delegate.isDebugEnabled) { - return - } - - withMdc { - val formattedMessage = MessageFormatter.format(format, arg1, arg2).message - delegate.log(null, fqcn, LocationAwareLogger.DEBUG_INT, formattedMessage, arrayOf(arg1, arg2), null) - } - } - - override fun debug(format: String?, argArray: Array<Any?>) { - if (!delegate.isDebugEnabled) { - return - } - - withMdc { - val ft = MessageFormatter.arrayFormat(format, argArray) - delegate.log(null, fqcn, LocationAwareLogger.DEBUG_INT, ft.message, ft.argArray, ft.throwable) - } - } - - override fun debug(msg: String?, t: Throwable?) { - if (!delegate.isDebugEnabled) { - return - } - - withMdc { - delegate.log(null, fqcn, LocationAwareLogger.DEBUG_INT, msg, null, t) - } - } - - override fun debug(marker: Marker?, msg: String?) { - if (!delegate.isDebugEnabled) { - return - } - - withMdc { - delegate.log(marker, fqcn, LocationAwareLogger.DEBUG_INT, msg, null, null) - } - } - - override fun debug(marker: Marker?, format: String?, arg: Any?) { - if (!delegate.isDebugEnabled) { - return - } - - withMdc { - val ft = MessageFormatter.format(format, arg) - delegate.log(marker, fqcn, LocationAwareLogger.DEBUG_INT, ft.message, ft.argArray, ft.throwable) - } - } - - override fun debug(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) { - if (!delegate.isDebugEnabled) { - return - } - - withMdc { - val formattedMessage = MessageFormatter.format(format, arg1, arg2).message - delegate.log(marker, fqcn, LocationAwareLogger.DEBUG_INT, formattedMessage, arrayOf(arg1, arg2), null) - } - } - - override fun debug(marker: Marker?, format: String?, argArray: Array<Any?>) { - if (!delegate.isDebugEnabled) { - return - } - - withMdc { - val ft = MessageFormatter.arrayFormat(format, argArray) - delegate.log(marker, fqcn, LocationAwareLogger.DEBUG_INT, ft.message, argArray, ft.throwable) - } - } - - override fun debug(marker: Marker?, msg: String?, t: Throwable?) { - if (!delegate.isDebugEnabled) { - return - } - - withMdc { - delegate.log(marker, fqcn, LocationAwareLogger.DEBUG_INT, msg, null, t) - } - } - - override fun info(msg: String?) { - if (!delegate.isInfoEnabled) { - return - } - - withMdc { - delegate.log(null, fqcn, LocationAwareLogger.INFO_INT, msg, null, null) - } - } - - override fun info(format: String?, arg: Any?) { - if (!delegate.isInfoEnabled) { - return - } - - withMdc { - val formattedMessage = MessageFormatter.format(format, arg).message - delegate.log(null, fqcn, LocationAwareLogger.INFO_INT, formattedMessage, arrayOf(arg), null) - } - } - - override fun info(format: String?, arg1: Any?, arg2: Any?) { - if (!delegate.isInfoEnabled) { - return - } - - withMdc { - val formattedMessage = MessageFormatter.format(format, arg1, arg2).message - delegate.log(null, fqcn, LocationAwareLogger.INFO_INT, formattedMessage, arrayOf(arg1, arg2), null) - } - } - - override fun info(format: String?, argArray: Array<Any?>) { - if (!delegate.isInfoEnabled) { - return - } - - withMdc { - val formattedMessage = MessageFormatter.arrayFormat(format, argArray).message - delegate.log(null, fqcn, LocationAwareLogger.INFO_INT, formattedMessage, argArray, null) - } - } - - override fun info(msg: String?, t: Throwable?) { - if (!delegate.isInfoEnabled) { - return - } - - withMdc { - delegate.log(null, fqcn, LocationAwareLogger.INFO_INT, msg, null, t) - } - } - - override fun info(marker: Marker?, msg: String?) { - if (!delegate.isInfoEnabled) { - return - } - - withMdc { - delegate.log(marker, fqcn, LocationAwareLogger.INFO_INT, msg, null, null) - } - } - - override fun info(marker: Marker?, format: String?, arg: Any?) { - if (!delegate.isInfoEnabled) { - return - } - - withMdc { - val formattedMessage = MessageFormatter.format(format, arg).message - delegate.log(marker, fqcn, LocationAwareLogger.INFO_INT, formattedMessage, arrayOf(arg), null) - } - } - - override fun info(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) { - if (!delegate.isInfoEnabled) { - return - } - - withMdc { - val formattedMessage = MessageFormatter.format(format, arg1, arg2).message - delegate.log(marker, fqcn, LocationAwareLogger.INFO_INT, formattedMessage, arrayOf(arg1, arg2), null) - } - } - - override fun info(marker: Marker?, format: String?, argArray: Array<Any?>) { - if (!delegate.isInfoEnabled) { - return - } - - withMdc { - val formattedMessage = MessageFormatter.arrayFormat(format, argArray).message - delegate.log(marker, fqcn, LocationAwareLogger.INFO_INT, formattedMessage, argArray, null) - } - } - - override fun info(marker: Marker?, msg: String?, t: Throwable?) { - if (!delegate.isInfoEnabled) { - return - } - - withMdc { - delegate.log(marker, fqcn, LocationAwareLogger.INFO_INT, msg, null, t) - } - } - - override fun warn(msg: String?) { - if (!delegate.isWarnEnabled) { - return - } - - withMdc { - delegate.log(null, fqcn, LocationAwareLogger.WARN_INT, msg, null, null) - } - } - - override fun warn(format: String?, arg: Any?) { - if (!delegate.isWarnEnabled) { - return - } - - withMdc { - val formattedMessage = MessageFormatter.format(format, arg).message - delegate.log(null, fqcn, LocationAwareLogger.WARN_INT, formattedMessage, arrayOf(arg), null) - } - } - - override fun warn(format: String?, arg1: Any?, arg2: Any?) { - if (!delegate.isWarnEnabled) { - return - } - - withMdc { - val formattedMessage = MessageFormatter.format(format, arg1, arg2).message - delegate.log(null, fqcn, LocationAwareLogger.WARN_INT, formattedMessage, arrayOf(arg1, arg2), null) - } - } - - override fun warn(format: String?, argArray: Array<Any?>) { - if (!delegate.isWarnEnabled) { - return - } - - withMdc { - val formattedMessage = MessageFormatter.arrayFormat(format, argArray).message - delegate.log(null, fqcn, LocationAwareLogger.WARN_INT, formattedMessage, argArray, null) - } - } - - override fun warn(msg: String?, t: Throwable?) { - if (!delegate.isWarnEnabled) { - return - } - - withMdc { - delegate.log(null, fqcn, LocationAwareLogger.WARN_INT, msg, null, t) - } - } - - override fun warn(marker: Marker?, msg: String?) { - if (!delegate.isWarnEnabled) { - return - } - - withMdc { - delegate.log(marker, fqcn, LocationAwareLogger.WARN_INT, msg, null, null) - } - } - - override fun warn(marker: Marker?, format: String?, arg: Any?) { - if (!delegate.isWarnEnabled) { - return - } - - withMdc { - val formattedMessage = MessageFormatter.format(format, arg).message - delegate.log(marker, fqcn, LocationAwareLogger.WARN_INT, formattedMessage, arrayOf(arg), null) - } - } - - override fun warn(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) { - if (!delegate.isWarnEnabled) { - return - } - - withMdc { - val formattedMessage = MessageFormatter.format(format, arg1, arg2).message - delegate.log(marker, fqcn, LocationAwareLogger.WARN_INT, formattedMessage, arrayOf(arg1, arg2), null) - } - } - - override fun warn(marker: Marker?, format: String?, argArray: Array<Any?>) { - if (!delegate.isWarnEnabled) { - return - } - - withMdc { - val formattedMessage = MessageFormatter.arrayFormat(format, argArray).message - delegate.log(marker, fqcn, LocationAwareLogger.WARN_INT, formattedMessage, argArray, null) - } - } - - override fun warn(marker: Marker?, msg: String?, t: Throwable?) { - if (!delegate.isWarnEnabled) { - return - } - - withMdc { - delegate.log(marker, fqcn, LocationAwareLogger.WARN_INT, msg, null, t) - } - } - - override fun error(msg: String?) { - if (!delegate.isErrorEnabled) { - return - } - - withMdc { - delegate.log(null, fqcn, LocationAwareLogger.ERROR_INT, msg, null, null) - } - } - - override fun error(format: String?, arg: Any?) { - if (!delegate.isErrorEnabled) { - return - } - - withMdc { - val formattedMessage = MessageFormatter.format(format, arg).message - delegate.log(null, fqcn, LocationAwareLogger.ERROR_INT, formattedMessage, arrayOf(arg), null) - } - } - - override fun error(format: String?, arg1: Any?, arg2: Any?) { - if (!delegate.isErrorEnabled) { - return - } - - withMdc { - val formattedMessage = MessageFormatter.format(format, arg1, arg2).message - delegate.log(null, fqcn, LocationAwareLogger.ERROR_INT, formattedMessage, arrayOf(arg1, arg2), null) - } - } - - override fun error(format: String?, argArray: Array<Any?>) { - if (!delegate.isErrorEnabled) { - return - } - - withMdc { - val formattedMessage = MessageFormatter.arrayFormat(format, argArray).message - delegate.log(null, fqcn, LocationAwareLogger.ERROR_INT, formattedMessage, argArray, null) - } - } - - override fun error(msg: String?, t: Throwable?) { - if (!delegate.isErrorEnabled) { - return - } - - withMdc { - delegate.log(null, fqcn, LocationAwareLogger.ERROR_INT, msg, null, t) - } - } - - override fun error(marker: Marker?, msg: String?) { - if (!delegate.isErrorEnabled) { - return - } - - withMdc { - delegate.log(marker, fqcn, LocationAwareLogger.ERROR_INT, msg, null, null) - } - } - - override fun error(marker: Marker?, format: String?, arg: Any?) { - if (!delegate.isErrorEnabled) { - return - } - - withMdc { - val formattedMessage = MessageFormatter.format(format, arg).message - delegate.log(marker, fqcn, LocationAwareLogger.ERROR_INT, formattedMessage, arrayOf(arg), null) - } - } - - override fun error(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) { - if (!delegate.isErrorEnabled) { - return - } - - withMdc { - val formattedMessage = MessageFormatter.format(format, arg1, arg2).message - delegate.log(marker, fqcn, LocationAwareLogger.ERROR_INT, formattedMessage, arrayOf(arg1, arg2), null) - } - } - - override fun error(marker: Marker?, format: String?, argArray: Array<Any?>) { - if (!delegate.isErrorEnabled) { - return - } - - withMdc { - val formattedMessage = MessageFormatter.arrayFormat(format, argArray).message - delegate.log(marker, fqcn, LocationAwareLogger.ERROR_INT, formattedMessage, argArray, null) - } - } - - override fun error(marker: Marker?, msg: String?, t: Throwable?) { - if (!delegate.isErrorEnabled) { - return - } - - withMdc { - delegate.log(marker, fqcn, LocationAwareLogger.ERROR_INT, msg, null, t) - } - } -} diff --git a/simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/logging/LocationIgnorantLoggerImpl.kt b/simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/logging/LocationIgnorantLoggerImpl.kt deleted file mode 100644 index 856cecfa..00000000 --- a/simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/logging/LocationIgnorantLoggerImpl.kt +++ /dev/null @@ -1,440 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2019 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 com.atlarge.odcsim.engine.omega.logging - -import com.atlarge.odcsim.SimulationContext -import org.slf4j.Logger -import org.slf4j.Marker - -/** - * A [Logger] implementation that is not aware of the calling location. - * - * @param ctx The owning [SimulationContext] of this logger. - * @param delegate The [Logger] to delegate the messages to. - */ -internal class LocationIgnorantLoggerImpl( - ctx: SimulationContext, - private val delegate: Logger -) : LoggerImpl(ctx), Logger by delegate { - override fun warn(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) { - if (!isWarnEnabled) { - return - } - - withMdc { delegate.warn(marker, format, arg1, arg2) } - } - - override fun warn(format: String?, arg1: Any?, arg2: Any?) { - if (!isWarnEnabled) { - return - } - - withMdc { delegate.warn(format, arg1, arg2) } - } - - override fun warn(msg: String?) { - if (!isWarnEnabled) { - return - } - - withMdc { delegate.warn(msg) } - } - - override fun warn(marker: Marker?, format: String?, arg: Any?) { - if (!isWarnEnabled) { - return - } - - withMdc { delegate.warn(marker, format, arg) } - } - - override fun warn(marker: Marker?, format: String?, vararg arguments: Any?) { - if (!isWarnEnabled) { - return - } - - withMdc { delegate.warn(marker, format, arguments) } - } - - override fun warn(format: String?, arg: Any?) { - if (!isWarnEnabled) { - return - } - - withMdc { delegate.warn(format, arg) } - } - - override fun warn(marker: Marker?, msg: String?) { - if (!isWarnEnabled) { - return - } - - withMdc { delegate.warn(marker, msg) } - } - - override fun warn(msg: String?, t: Throwable?) { - if (!isWarnEnabled) { - return - } - - withMdc { delegate.warn(msg, t) } - } - - override fun warn(format: String?, vararg arguments: Any?) { - if (!isWarnEnabled) { - return - } - - withMdc { delegate.warn(format, *arguments) } - } - - override fun warn(marker: Marker?, msg: String?, t: Throwable?) { - if (!isWarnEnabled) { - return - } - - withMdc { delegate.warn(marker, msg, t) } - } - - override fun info(marker: Marker?, format: String?, vararg arguments: Any?) { - if (!isInfoEnabled) { - return - } - - withMdc { delegate.info(marker, format, *arguments) } - } - - override fun info(format: String?, arg: Any?) { - if (!isInfoEnabled) { - return - } - - withMdc { delegate.info(format, arg) } - } - - override fun info(marker: Marker?, msg: String?, t: Throwable?) { - if (!isInfoEnabled) { - return - } - - withMdc { delegate.info(marker, msg, t) } - } - - override fun info(msg: String?) { - if (!isInfoEnabled) { - return - } - - withMdc { delegate.info(msg) } - } - - override fun info(format: String?, vararg arguments: Any?) { - if (!isInfoEnabled) { - return - } - - withMdc { delegate.info(format, *arguments) } - } - - override fun info(format: String?, arg1: Any?, arg2: Any?) { - if (!isInfoEnabled) { - return - } - - withMdc { delegate.info(format, arg1, arg2) } - } - - override fun info(marker: Marker?, msg: String?) { - if (!isInfoEnabled) { - return - } - - withMdc { delegate.info(marker, msg) } - } - - override fun info(marker: Marker?, format: String?, arg: Any?) { - if (!isInfoEnabled) { - return - } - - withMdc { delegate.info(marker, format, arg) } - } - - override fun info(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) { - if (!isInfoEnabled) { - return - } - - withMdc { delegate.info(marker, format, arg1, arg2) } - } - - override fun info(msg: String?, t: Throwable?) { - if (!isInfoEnabled) { - return - } - - withMdc { delegate.info(msg, t) } - } - - override fun error(msg: String?) { - if (!isErrorEnabled) { - return - } - - withMdc { delegate.error(msg) } - } - - override fun error(marker: Marker?, msg: String?) { - if (!isErrorEnabled) { - return - } - - withMdc { delegate.error(marker, msg) } - } - - override fun error(format: String?, vararg arguments: Any?) { - if (!isErrorEnabled) { - return - } - - withMdc { delegate.error(format, *arguments) } - } - - override fun error(format: String?, arg: Any?) { - if (!isErrorEnabled) { - return - } - - withMdc { delegate.error(format, arg) } - } - - override fun error(msg: String?, t: Throwable?) { - if (!isErrorEnabled) { - return - } - - withMdc { delegate.error(msg, t) } - } - - override fun error(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) { - if (!isErrorEnabled) { - return - } - - withMdc { delegate.error(marker, format, arg1, arg2) } - } - - override fun error(marker: Marker?, format: String?, vararg arguments: Any?) { - if (!isErrorEnabled) { - return - } - - withMdc { delegate.error(marker, format, *arguments) } - } - - override fun error(marker: Marker?, msg: String?, t: Throwable?) { - if (!isErrorEnabled) { - return - } - - withMdc { delegate.error(marker, msg, t) } - } - - override fun error(format: String?, arg1: Any?, arg2: Any?) { - if (!isErrorEnabled) { - return - } - - withMdc { delegate.error(format, arg1, arg2) } - } - - override fun error(marker: Marker?, format: String?, arg: Any?) { - if (!isErrorEnabled) { - return - } - - withMdc { delegate.error(marker, format, arg) } - } - - override fun debug(format: String?, vararg arguments: Any?) { - if (!isDebugEnabled) { - return - } - - withMdc { delegate.debug(format, *arguments) } - } - - override fun debug(format: String?, arg1: Any?, arg2: Any?) { - if (!isDebugEnabled) { - return - } - - withMdc { delegate.debug(format, arg1, arg2) } - } - - override fun debug(msg: String?, t: Throwable?) { - if (!isDebugEnabled) { - return - } - - withMdc { delegate.debug(msg, t) } - } - - override fun debug(format: String?, arg: Any?) { - if (!isDebugEnabled) { - return - } - - withMdc { delegate.debug(format, arg) } - } - - override fun debug(marker: Marker?, msg: String?) { - if (!isDebugEnabled) { - return - } - - withMdc { delegate.debug(marker, msg) } - } - - override fun debug(msg: String?) { - if (!isDebugEnabled) { - return - } - - withMdc { delegate.debug(msg) } - } - - override fun debug(marker: Marker?, msg: String?, t: Throwable?) { - if (!isDebugEnabled) { - return - } - - withMdc { delegate.debug(marker, msg, t) } - } - - override fun debug(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) { - if (!isDebugEnabled) { - return - } - - withMdc { delegate.debug(marker, format, arg1, arg2) } - } - - override fun debug(marker: Marker?, format: String?, arg: Any?) { - if (!isDebugEnabled) { - return - } - - withMdc { delegate.debug(marker, format, arg) } - } - - override fun debug(marker: Marker?, format: String?, vararg arguments: Any?) { - if (!isDebugEnabled) { - return - } - - withMdc { delegate.debug(marker, format, *arguments) } - } - - override fun trace(format: String?, arg: Any?) { - if (!isTraceEnabled) { - return - } - - withMdc { delegate.trace(format, arg) } - } - - override fun trace(marker: Marker?, msg: String?) { - if (!isTraceEnabled) { - return - } - - withMdc { delegate.trace(marker, msg) } - } - - override fun trace(msg: String?) { - if (!isTraceEnabled) { - return - } - - withMdc { delegate.trace(msg) } - } - - override fun trace(msg: String?, t: Throwable?) { - if (!isTraceEnabled) { - return - } - - withMdc { delegate.trace(msg, t) } - } - - override fun trace(format: String?, arg1: Any?, arg2: Any?) { - if (!isTraceEnabled) { - return - } - - withMdc { delegate.trace(format, arg1, arg2) } - } - - override fun trace(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) { - if (!isTraceEnabled) { - return - } - - withMdc { delegate.trace(marker, format, arg1, arg2) } - } - - override fun trace(marker: Marker?, format: String?, arg: Any?) { - if (!isTraceEnabled) { - return - } - - withMdc { delegate.trace(marker, format, arg) } - } - - override fun trace(marker: Marker?, format: String?, vararg argArray: Any?) { - if (!isTraceEnabled) { - return - } - - withMdc { delegate.trace(marker, format, *argArray) } - } - - override fun trace(marker: Marker?, msg: String?, t: Throwable?) { - if (!isTraceEnabled) { - return - } - - withMdc { delegate.trace(marker, msg, t) } - } - - override fun trace(format: String?, vararg arguments: Any?) { - if (!isTraceEnabled) { - return - } - - withMdc { delegate.trace(format, *arguments) } - } -} diff --git a/simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/logging/LoggerImpl.kt b/simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/logging/LoggerImpl.kt deleted file mode 100644 index 1adcfdc0..00000000 --- a/simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/logging/LoggerImpl.kt +++ /dev/null @@ -1,74 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2019 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 com.atlarge.odcsim.engine.omega.logging - -import com.atlarge.odcsim.SimulationContext -import org.slf4j.Logger -import org.slf4j.LoggerFactory -import org.slf4j.MDC -import org.slf4j.spi.LocationAwareLogger - -/** - * An actor-specific [Logger] implementation. - * - * @param ctx The owning [SimulationContext] of this logger. - */ -internal abstract class LoggerImpl internal constructor(protected val ctx: SimulationContext) : Logger { - /** - * Configure [MDC] with actor-specific information. - */ - protected inline fun withMdc(block: () -> Unit) { - MDC.put(MDC_PROCESS_REF, ctx.domain.name) - MDC.put(MDC_PROCESS_TIME, String.format("%d", ctx.clock.millis())) - try { - block() - } finally { - MDC.remove(MDC_PROCESS_TIME) - MDC.remove(MDC_PROCESS_REF) - } - } - - /** - * Mapped Diagnostic Context (MDC) attribute names. - */ - companion object { - val MDC_PROCESS_TIME = "process.time" - val MDC_PROCESS_REF = "process.ref" - - /** - * Create a [Logger] for the specified [ActorContext]. - * - * @param ctx The actor context to create the logger for. - */ - operator fun invoke(ctx: SimulationContext): Logger { - val logger = LoggerFactory.getLogger(ctx.javaClass) - return if (logger is LocationAwareLogger) { - LocationAwareLoggerImpl(ctx, logger) - } else { - LocationIgnorantLoggerImpl(ctx, logger) - } - } - } -} diff --git a/simulator/odcsim/odcsim-engine-omega/src/main/resources/META-INF/services/com.atlarge.odcsim.SimulationEngineProvider b/simulator/odcsim/odcsim-engine-omega/src/main/resources/META-INF/services/com.atlarge.odcsim.SimulationEngineProvider deleted file mode 100644 index 1131cebd..00000000 --- a/simulator/odcsim/odcsim-engine-omega/src/main/resources/META-INF/services/com.atlarge.odcsim.SimulationEngineProvider +++ /dev/null @@ -1 +0,0 @@ -com.atlarge.odcsim.engine.omega.OmegaSimulationEngineProvider diff --git a/simulator/opendc/build.gradle.kts b/simulator/opendc-compute/build.gradle.kts index cc3f3add..bf920306 100644 --- a/simulator/opendc/build.gradle.kts +++ b/simulator/opendc-compute/build.gradle.kts @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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 @@ -21,3 +19,5 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ + +description = "Cloud computing fabric controller of OpenDC" diff --git a/simulator/opendc/opendc-compute/build.gradle.kts b/simulator/opendc-compute/opendc-compute-core/build.gradle.kts index acdcd5a7..9682b50f 100644 --- a/simulator/opendc/opendc-compute/build.gradle.kts +++ b/simulator/opendc-compute/opendc-compute-core/build.gradle.kts @@ -1,7 +1,5 @@ /* - * MIT License - * - * 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 @@ -22,7 +20,7 @@ * SOFTWARE. */ -description = "Cloud computing fabric simulation model" +description = "Core implementation of the OpenDC Compute service" /* Build configuration */ plugins { @@ -30,12 +28,12 @@ plugins { } dependencies { - implementation(kotlin("stdlib")) - api(project(":odcsim:odcsim-api")) - api(project(":opendc:opendc-core")) + api(project(":opendc-core")) + implementation(project(":opendc-utils")) implementation("io.github.microutils:kotlin-logging:1.7.9") - testRuntimeOnly(project(":odcsim:odcsim-engine-omega")) + 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}") diff --git a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/Flavor.kt b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/Flavor.kt index a49d3abf..e5ca115f 100644 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/Flavor.kt +++ b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/Flavor.kt @@ -22,7 +22,7 @@ * SOFTWARE. */ -package com.atlarge.opendc.compute.core +package org.opendc.compute.core /** * Flavors define the compute and memory capacity of [Server] instance. To put it simply, a flavor is an available diff --git a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/Server.kt b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/Server.kt index fd0fc836..948f622f 100644 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/Server.kt +++ b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/Server.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,14 +20,14 @@ * SOFTWARE. */ -package com.atlarge.opendc.compute.core +package org.opendc.compute.core -import com.atlarge.opendc.compute.core.image.Image -import com.atlarge.opendc.core.resource.Resource -import com.atlarge.opendc.core.resource.TagContainer -import com.atlarge.opendc.core.services.ServiceRegistry -import java.util.UUID import kotlinx.coroutines.flow.Flow +import org.opendc.compute.core.image.Image +import org.opendc.core.resource.Resource +import org.opendc.core.resource.TagContainer +import org.opendc.core.services.ServiceRegistry +import java.util.UUID /** * A server instance that is running on some physical or virtual machine. diff --git a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/ServerEvent.kt b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/ServerEvent.kt index 1595937c..e9212832 100644 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/ServerEvent.kt +++ b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/ServerEvent.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,9 +20,7 @@ * SOFTWARE. */ -package com.atlarge.opendc.compute.core - -import com.atlarge.opendc.core.services.ServiceKey +package org.opendc.compute.core /** * An event that is emitted by a [Server]. @@ -42,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/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/ServerState.kt b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/ServerState.kt index 27372a5e..4b9d7c13 100644 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/ServerState.kt +++ b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/ServerState.kt @@ -22,7 +22,7 @@ * SOFTWARE. */ -package com.atlarge.opendc.compute.core +package org.opendc.compute.core /** * An enumeration describing the possible states of a server. diff --git a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/image/EmptyImage.kt b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/image/EmptyImage.kt index 8f6c4682..01f86a1b 100644 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/image/EmptyImage.kt +++ b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/image/EmptyImage.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,19 +20,16 @@ * SOFTWARE. */ -package com.atlarge.opendc.compute.core.image +package org.opendc.compute.core.image -import com.atlarge.opendc.compute.core.execution.ServerContext -import com.atlarge.opendc.core.resource.TagContainer +import org.opendc.core.resource.TagContainer import java.util.UUID /** * An empty boot disk [Image] that exits immediately on start. */ -object EmptyImage : Image { +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/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/image/Image.kt b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/image/Image.kt index 52d4d7b5..e481fcc3 100644 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/image/Image.kt +++ b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/image/Image.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,10 +20,9 @@ * SOFTWARE. */ -package com.atlarge.opendc.compute.core.image +package org.opendc.compute.core.image -import com.atlarge.opendc.compute.core.execution.ServerContext -import com.atlarge.opendc.core.resource.Resource +import org.opendc.core.resource.Resource /** * An image containing a bootable operating system that can directly be executed by physical or virtual server. @@ -35,12 +32,4 @@ import com.atlarge.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/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/metal/Metadata.kt b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/metal/Metadata.kt index a3a851fe..11eadd87 100644 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/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 com.atlarge.opendc.compute.metal +package org.opendc.compute.core.metal /* * Common metadata keys for bare-metal nodes. @@ -31,4 +31,4 @@ package com.atlarge.opendc.compute.metal /** * The cluster to which the node belongs. */ -const val NODE_CLUSTER = "bare-metal:cluster" +public const val NODE_CLUSTER: String = "bare-metal:cluster" diff --git a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/metal/Node.kt b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/metal/Node.kt index cb637aea..6d9506f1 100644 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/metal/Node.kt +++ b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/metal/Node.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,13 +20,13 @@ * SOFTWARE. */ -package com.atlarge.opendc.compute.metal +package org.opendc.compute.core.metal -import com.atlarge.opendc.compute.core.Server -import com.atlarge.opendc.compute.core.image.Image -import com.atlarge.opendc.core.Identity -import java.util.UUID import kotlinx.coroutines.flow.Flow +import org.opendc.compute.core.Server +import org.opendc.compute.core.image.Image +import org.opendc.core.Identity +import java.util.UUID /** * A bare-metal compute node. diff --git a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/metal/NodeEvent.kt b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/metal/NodeEvent.kt index 7719db24..4423e2bf 100644 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/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 com.atlarge.opendc.compute.metal +package org.opendc.compute.core.metal /** * An event that is emitted by a [Node]. diff --git a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/metal/NodeState.kt b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/metal/NodeState.kt index ca9cf509..bdc4841e 100644 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/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 com.atlarge.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/opendc-compute/src/main/kotlin/com/atlarge/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 17d8ee53..9db57127 100644 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/metal/driver/BareMetalDriver.kt +++ b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/metal/driver/BareMetalDriver.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,21 +20,19 @@ * SOFTWARE. */ -package com.atlarge.opendc.compute.metal.driver +package org.opendc.compute.core.metal.driver -import com.atlarge.opendc.compute.core.Server -import com.atlarge.opendc.compute.core.image.Image -import com.atlarge.opendc.compute.metal.Node -import com.atlarge.opendc.core.failure.FailureDomain -import com.atlarge.opendc.core.power.Powerable -import com.atlarge.opendc.core.services.AbstractServiceKey -import java.util.UUID import kotlinx.coroutines.flow.Flow +import org.opendc.compute.core.Server +import org.opendc.compute.core.image.Image +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. */ @@ -84,5 +80,5 @@ public interface BareMetalDriver : Powerable, FailureDomain { /** * A key that allows access to the [BareMetalDriver] instance from a [Server] that runs on the bare-metal machine. */ - companion object Key : AbstractServiceKey<BareMetalDriver>(UUID.randomUUID(), "bare-metal:driver") + public companion object Key : AbstractServiceKey<BareMetalDriver>(UUID.randomUUID(), "bare-metal:driver") } diff --git a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/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 a54d8df4..bad5b47c 100644 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/metal/service/ProvisioningService.kt +++ b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/metal/service/ProvisioningService.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,12 +20,12 @@ * SOFTWARE. */ -package com.atlarge.opendc.compute.metal.service +package org.opendc.compute.core.metal.service -import com.atlarge.opendc.compute.core.image.Image -import com.atlarge.opendc.compute.metal.Node -import com.atlarge.opendc.compute.metal.driver.BareMetalDriver -import com.atlarge.opendc.core.services.AbstractServiceKey +import org.opendc.compute.core.image.Image +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 /** @@ -62,5 +60,5 @@ public interface ProvisioningService { /** * The service key of this service. */ - companion object Key : AbstractServiceKey<ProvisioningService>(UUID.randomUUID(), "provisioner") + public companion object Key : AbstractServiceKey<ProvisioningService>(UUID.randomUUID(), "provisioner") } diff --git a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/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 f6b236ae..5222f2fb 100644 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/metal/service/SimpleProvisioningService.kt +++ b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/metal/service/SimpleProvisioningService.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,46 +20,43 @@ * SOFTWARE. */ -package com.atlarge.opendc.compute.metal.service +package org.opendc.compute.core.metal.service -import com.atlarge.odcsim.Domain -import com.atlarge.opendc.compute.core.image.Image -import com.atlarge.opendc.compute.metal.Node -import com.atlarge.opendc.compute.metal.driver.BareMetalDriver import kotlinx.coroutines.CancellationException -import kotlinx.coroutines.withContext +import org.opendc.compute.core.image.Image +import org.opendc.compute.core.metal.Node +import org.opendc.compute.core.metal.driver.BareMetalDriver /** * A very basic implementation of the [ProvisioningService]. */ -public class SimpleProvisioningService(val domain: Domain) : ProvisioningService { +public class SimpleProvisioningService : ProvisioningService { /** * The active nodes in this service. */ private val nodes: MutableMap<Node, BareMetalDriver> = mutableMapOf() - override suspend fun create(driver: BareMetalDriver): Node = withContext(domain.coroutineContext) { + override suspend fun create(driver: BareMetalDriver): Node { val node = driver.init() nodes[node] = driver - return@withContext node + return node } - override suspend fun nodes(): Set<Node> = withContext(domain.coroutineContext) { nodes.keys } + override suspend fun nodes(): Set<Node> = nodes.keys - override suspend fun refresh(node: Node): Node = withContext(domain.coroutineContext) { - return@withContext nodes[node]!!.refresh() + override suspend fun refresh(node: Node): Node { + return nodes[node]!!.refresh() } - override suspend fun deploy(node: Node, image: Image): Node = withContext(domain.coroutineContext) { + override suspend fun deploy(node: Node, image: Image): Node { val driver = nodes[node]!! driver.setImage(image) - val newNode = driver.reboot() - return@withContext newNode + return driver.reboot() } - override suspend fun stop(node: Node): Node = withContext(domain.coroutineContext) { + override suspend fun stop(node: Node): Node { val driver = nodes[node]!! - try { + return try { driver.stop() } catch (e: CancellationException) { node diff --git a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/Hypervisor.kt b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/virt/Hypervisor.kt index 1e7e351f..1ae52baa 100644 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/Hypervisor.kt +++ b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/virt/Hypervisor.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,11 +20,11 @@ * SOFTWARE. */ -package com.atlarge.opendc.compute.virt +package org.opendc.compute.core.virt -import com.atlarge.opendc.core.Identity -import java.util.UUID import kotlinx.coroutines.flow.Flow +import org.opendc.core.Identity +import java.util.UUID /** * A hypervisor (or virtual machine monitor) is software or firmware that virtualizes the host compute environment diff --git a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/HypervisorEvent.kt b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/virt/HypervisorEvent.kt index 7c088bc8..9fb437de 100644 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/HypervisorEvent.kt +++ b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/virt/HypervisorEvent.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,10 +20,10 @@ * SOFTWARE. */ -package com.atlarge.opendc.compute.virt +package org.opendc.compute.core.virt -import com.atlarge.opendc.compute.core.Server -import com.atlarge.opendc.compute.virt.driver.VirtDriver +import org.opendc.compute.core.Server +import org.opendc.compute.core.virt.driver.VirtDriver /** * An event that is emitted by a [VirtDriver]. diff --git a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/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 0586ae00..6fe84ea6 100644 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/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 com.atlarge.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/opendc-compute/src/main/kotlin/com/atlarge/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 b1844f67..5ecfd357 100644 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/driver/VirtDriver.kt +++ b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/virt/driver/VirtDriver.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,15 +20,14 @@ * SOFTWARE. */ -package com.atlarge.opendc.compute.virt.driver +package org.opendc.compute.core.virt.driver -import com.atlarge.opendc.compute.core.Flavor -import com.atlarge.opendc.compute.core.Server -import com.atlarge.opendc.compute.core.image.Image -import com.atlarge.opendc.compute.virt.HypervisorEvent -import com.atlarge.opendc.core.services.AbstractServiceKey -import java.util.UUID import kotlinx.coroutines.flow.Flow +import org.opendc.compute.core.Server +import org.opendc.compute.core.image.Image +import org.opendc.compute.core.virt.HypervisorEvent +import org.opendc.core.services.AbstractServiceKey +import java.util.UUID /** * A driver interface for a hypervisor running on some host server and communicating with the central compute service to @@ -50,7 +47,11 @@ public interface VirtDriver { * @param flavor The flavor of the server which this driver is controlling. * @return The virtual server spawned by this method. */ - public suspend fun spawn(name: String, image: Image, flavor: Flavor): Server + public suspend fun spawn( + name: String, + image: Image, + flavor: org.opendc.compute.core.Flavor + ): Server - companion object Key : AbstractServiceKey<VirtDriver>(UUID.randomUUID(), "virtual-driver") + public companion object Key : AbstractServiceKey<VirtDriver>(UUID.randomUUID(), "virtual-driver") } diff --git a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/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 c3fb99f9..abd2fc95 100644 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/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 com.atlarge.opendc.compute.virt.service +package org.opendc.compute.core.virt.service /** * An event that is emitted by the [VirtProvisioningService]. @@ -36,7 +36,7 @@ public sealed class VirtProvisioningEvent { /** * An event emitted for writing metrics. */ - data class MetricsAvailable( + public data class MetricsAvailable( override val provisioner: VirtProvisioningService, public val totalHostCount: Int, public val availableHostCount: Int, diff --git a/simulator/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/SimulationEngine.kt b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/virt/service/VirtProvisioningService.kt index db05cb1d..ab96e0a3 100644 --- a/simulator/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/SimulationEngine.kt +++ b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/virt/service/VirtProvisioningService.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2018 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,37 +20,42 @@ * SOFTWARE. */ -package com.atlarge.odcsim +package org.opendc.compute.core.virt.service + +import kotlinx.coroutines.flow.Flow +import org.opendc.compute.core.Server +import org.opendc.compute.core.image.Image +import org.opendc.compute.core.virt.driver.VirtDriver /** - * An engine for managing logical processes represented as [Behavior] during simulation. - * - * An implementation of this interface should be provided by an engine. See for example *odcsim-engine-omega*, - * which is the reference implementation of the *odcsim* API. + * A service for VM provisioning on a cloud. */ -public interface SimulationEngine { - /** - * The name of this engine instance, used to distinguish between multiple engines running within the same JVM. - */ - public val name: String - +public interface VirtProvisioningService { /** - * Construct an anonymous root simulation domain. + * The events emitted by the service. */ - public fun newDomain(): Domain + public val events: Flow<VirtProvisioningEvent> /** - * Construct a new root simulation domain with the specified [name]. + * Obtain the active hypervisors for this provisioner. */ - public fun newDomain(name: String): Domain + public suspend fun drivers(): Set<VirtDriver> /** - * Run the simulation. + * Submit the specified [Image] to the provisioning service. + * + * @param name The name of the server to deploy. + * @param image The image to be deployed. + * @param flavor The flavor of the machine instance to run this [image] on. */ - public suspend fun run() + public suspend fun deploy( + name: String, + image: Image, + flavor: org.opendc.compute.core.Flavor + ): Server /** - * Terminates this engine in an asynchronous fashion. + * Terminate the provisioning service releasing all the leased bare-metal machines. */ public suspend fun terminate() } diff --git a/simulator/opendc-compute/opendc-compute-core/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 new file mode 100644 index 00000000..6c724277 --- /dev/null +++ b/simulator/opendc-compute/opendc-compute-core/src/main/kotlin/org/opendc/compute/core/workload/VmWorkload.kt @@ -0,0 +1,47 @@ +/* + * 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.workload + +import org.opendc.compute.core.image.Image +import org.opendc.core.User +import org.opendc.core.workload.Workload +import java.util.UUID + +/** + * A workload that represents a VM. + * + * @property uid A unique identified of this VM. + * @property name The name of this VM. + * @property owner The owner of the VM. + * @property image The image of the VM. + */ +public data class VmWorkload( + override val uid: UUID, + override val name: String, + override val owner: User, + val image: Image +) : Workload { + override fun equals(other: Any?): Boolean = other is VmWorkload && uid == other.uid + + override fun hashCode(): Int = uid.hashCode() +} diff --git a/simulator/odcsim/odcsim-engine-omega/build.gradle.kts b/simulator/opendc-compute/opendc-compute-simulator/build.gradle.kts index 98e2469e..d7570e54 100644 --- a/simulator/odcsim/odcsim-engine-omega/build.gradle.kts +++ b/simulator/opendc-compute/opendc-compute-simulator/build.gradle.kts @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2018 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,26 +20,23 @@ * SOFTWARE. */ -description = "Single-threaded reference implementation for the odcsim API" +description = "Simulator for OpenDC Compute" /* Build configuration */ plugins { `kotlin-library-convention` } -/* Project configuration */ -repositories { - jcenter() -} - dependencies { - api(project(":odcsim:odcsim-api")) - - implementation(kotlin("stdlib")) - implementation("org.jetbrains:annotations:17.0.0") + 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}") - testRuntimeOnly("org.slf4j:slf4j-simple:${Library.SLF4J}") } 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/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/HypervisorView.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/HypervisorView.kt new file mode 100644 index 00000000..1a79523e --- /dev/null +++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/HypervisorView.kt @@ -0,0 +1,37 @@ +/* + * 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.compute.core.virt.driver.VirtDriver +import java.util.UUID + +public class HypervisorView( + public val uid: UUID, + public var server: Server, + public var numberOfActiveServers: Int, + public var availableMemory: Long, + public var provisionedCores: Int +) { + public lateinit var driver: VirtDriver +} 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/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/execution/ServerManagementContext.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimVirtDriverWorkload.kt index 5a9b725b..58b9408a 100644 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/execution/ServerManagementContext.kt +++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimVirtDriverWorkload.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,19 +20,19 @@ * SOFTWARE. */ -package com.atlarge.opendc.compute.core.execution +package org.opendc.compute.simulator -/** - * An extended [ServerContext] providing several methods for managing the execution context. - */ -public interface ServerManagementContext : ServerContext { - /** - * Initialize the management context. - */ - public suspend fun init() +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 - /** - * Terminate the execution of the server. - */ - public suspend fun exit(cause: Throwable? = null) + override suspend fun run(ctx: SimExecutionContext) { + coroutineScope { + driver = SimVirtDriver(this, ctx.clock, ctx) + driver.run() + } + } } diff --git a/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimVirtProvisioningService.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimVirtProvisioningService.kt new file mode 100644 index 00000000..e83370d7 --- /dev/null +++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimVirtProvisioningService.kt @@ -0,0 +1,393 @@ +/* + * 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 kotlinx.coroutines.flow.launchIn +import kotlinx.coroutines.flow.onEach +import mu.KotlinLogging +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.Image +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 + +@OptIn(ExperimentalCoroutinesApi::class) +public class SimVirtProvisioningService( + private val coroutineScope: CoroutineScope, + private val clock: Clock, + private val provisioningService: ProvisioningService, + 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() + + /** + * The available hypervisors. + */ + private val availableHypervisors: MutableSet<HypervisorView> = mutableSetOf() + + /** + * The incoming images to be processed by the provisioner. + */ + private val incomingImages: MutableSet<ImageView> = mutableSetOf() + + /** + * The active images in the system. + */ + private val activeImages: MutableSet<ImageView> = mutableSetOf() + + public var submittedVms: Int = 0 + public var queuedVms: Int = 0 + public var runningVms: Int = 0 + public var finishedVms: Int = 0 + public var unscheduledVms: Int = 0 + + private var maxCores = 0 + private var maxMemory = 0L + + /** + * The allocation logic to use. + */ + private val allocationLogic = allocationPolicy() + + /** + * The [EventFlow] to emit the events. + */ + internal val eventFlow = EventFlow<VirtProvisioningEvent>() + + override val events: Flow<VirtProvisioningEvent> = eventFlow + + init { + coroutineScope.launch { + val provisionedNodes = provisioningService.nodes() + provisionedNodes.forEach { node -> + 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) + } + } + } + } + + override suspend fun drivers(): Set<VirtDriver> { + return availableHypervisors.map { it.driver }.toSet() + } + + override suspend fun deploy( + name: String, + image: Image, + flavor: Flavor + ): Server { + eventFlow.emit( + VirtProvisioningEvent.MetricsAvailable( + this@SimVirtProvisioningService, + hypervisors.size, + availableHypervisors.size, + ++submittedVms, + runningVms, + finishedVms, + ++queuedVms, + unscheduledVms + ) + ) + + return suspendCancellableCoroutine<Server> { cont -> + val vmInstance = ImageView(name, image, flavor, cont) + incomingImages += vmInstance + requestCycle() + } + } + + override suspend fun terminate() { + val provisionedNodes = provisioningService.nodes() + provisionedNodes.forEach { node -> provisioningService.stop(node) } + } + + private var call: Job? = null + + private fun requestCycle() { + if (call != null) { + return + } + + val quantum = 300000 // 5 minutes in milliseconds + // We assume that the provisioner runs at a fixed slot every time quantum (e.g t=0, t=60, t=120). + // This is important because the slices of the VMs need to be aligned. + // We calculate here the delay until the next scheduling slot. + val delay = quantum - (clock.millis() % quantum) + + val call = coroutineScope.launch { + delay(delay) + this@SimVirtProvisioningService.call = null + schedule() + } + this.call = call + } + + private suspend fun schedule() { + val imagesToBeScheduled = incomingImages.toSet() + + for (imageInstance in imagesToBeScheduled) { + 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@SimVirtProvisioningService, + hypervisors.size, + availableHypervisors.size, + submittedVms, + runningVms, + finishedVms, + queuedVms, + ++unscheduledVms + ) + ) + + incomingImages -= imageInstance + + logger.warn("Failed to spawn ${imageInstance.image}: does not fit [${clock.millis()}]") + continue + } else { + break + } + } + + try { + logger.info { "[${clock.millis()}] Spawning ${imageInstance.image} on ${selectedHv.server.uid} ${selectedHv.server.name} ${selectedHv.server.flavor}" } + incomingImages -= imageInstance + + // Speculatively update the hypervisor view information to prevent other images in the queue from + // deciding on stale values. + selectedHv.numberOfActiveServers++ + selectedHv.provisionedCores += imageInstance.flavor.cpuCount + selectedHv.availableMemory -= requiredMemory // XXX Temporary hack + + val server = selectedHv.driver.spawn( + imageInstance.name, + imageInstance.image, + imageInstance.flavor + ) + imageInstance.server = server + imageInstance.continuation.resume(server) + + eventFlow.emit( + VirtProvisioningEvent.MetricsAvailable( + this@SimVirtProvisioningService, + hypervisors.size, + availableHypervisors.size, + submittedVms, + ++runningVms, + finishedVms, + --queuedVms, + unscheduledVms + ) + ) + activeImages += imageInstance + + server.events + .onEach { event -> + when (event) { + is ServerEvent.StateChanged -> { + if (event.server.state == ServerState.SHUTOFF) { + logger.info { "[${clock.millis()}] Server ${event.server.uid} ${event.server.name} ${event.server.flavor} finished." } + + eventFlow.emit( + VirtProvisioningEvent.MetricsAvailable( + this@SimVirtProvisioningService, + hypervisors.size, + availableHypervisors.size, + submittedVms, + --runningVms, + ++finishedVms, + queuedVms, + unscheduledVms + ) + ) + + activeImages -= imageInstance + selectedHv.provisionedCores -= server.flavor.cpuCount + + // Try to reschedule if needed + if (incomingImages.isNotEmpty()) { + requestCycle() + } + } + } + } + } + .launchIn(coroutineScope) + } catch (e: InsufficientMemoryOnServerException) { + logger.error("Failed to deploy VM", e) + + selectedHv.numberOfActiveServers-- + selectedHv.provisionedCores -= imageInstance.flavor.cpuCount + selectedHv.availableMemory += requiredMemory + } catch (e: Throwable) { + logger.error("Failed to deploy VM", e) + } + } + } + + private fun stateChanged(server: Server) { + when (server.state) { + ServerState.ACTIVE -> { + logger.debug { "[${clock.millis()}] Server ${server.uid} available: ${server.state}" } + + if (server in hypervisors) { + // Corner case for when the hypervisor already exists + availableHypervisors += hypervisors.getValue(server) + } else { + val hv = HypervisorView( + server.uid, + server, + 0, + server.flavor.memorySize, + 0 + ) + maxCores = max(maxCores, server.flavor.cpuCount) + maxMemory = max(maxMemory, server.flavor.memorySize) + hypervisors[server] = hv + } + + eventFlow.emit( + VirtProvisioningEvent.MetricsAvailable( + this@SimVirtProvisioningService, + hypervisors.size, + availableHypervisors.size, + submittedVms, + runningVms, + finishedVms, + queuedVms, + unscheduledVms + ) + ) + + // Re-schedule on the new machine + if (incomingImages.isNotEmpty()) { + requestCycle() + } + } + ServerState.SHUTOFF, ServerState.ERROR -> { + logger.debug { "[${clock.millis()}] Server ${server.uid} unavailable: ${server.state}" } + val hv = hypervisors[server] ?: return + availableHypervisors -= hv + + eventFlow.emit( + VirtProvisioningEvent.MetricsAvailable( + this@SimVirtProvisioningService, + hypervisors.size, + availableHypervisors.size, + submittedVms, + runningVms, + finishedVms, + queuedVms, + unscheduledVms + ) + ) + + if (incomingImages.isNotEmpty()) { + requestCycle() + } + } + else -> throw IllegalStateException() + } + } + + 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) + + requestCycle() + } + + public data class ImageView( + public val name: String, + public val image: Image, + public val flavor: Flavor, + public val continuation: Continuation<Server>, + public var server: Server? = null + ) +} diff --git a/simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/OmegaSimulationEngineProvider.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimWorkloadImage.kt index 5dba3233..b48de1d5 100644 --- a/simulator/odcsim/odcsim-engine-omega/src/main/kotlin/com/atlarge/odcsim/engine/omega/OmegaSimulationEngineProvider.kt +++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/SimWorkloadImage.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2018 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,16 +20,24 @@ * SOFTWARE. */ -package com.atlarge.odcsim.engine.omega +package org.opendc.compute.simulator -import com.atlarge.odcsim.SimulationEngine -import com.atlarge.odcsim.SimulationEngineProvider -import java.util.ServiceLoader +import org.opendc.compute.core.image.Image +import org.opendc.core.resource.TagContainer +import org.opendc.simulator.compute.workload.SimWorkload +import java.util.* /** - * An [SimulationEngineProvider] for the Omega engine, used by the [ServiceLoader] API to create - * [OmegaSimulationEngine] instances. + * 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 class OmegaSimulationEngineProvider : SimulationEngineProvider { - override operator fun invoke(name: String): SimulationEngine = OmegaSimulationEngine(name) -} +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/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/AllocationPolicy.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/AllocationPolicy.kt new file mode 100644 index 00000000..2018b9f2 --- /dev/null +++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/AllocationPolicy.kt @@ -0,0 +1,50 @@ +/* + * 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.allocation + +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, + */ +public interface AllocationPolicy { + /** + * The logic of the allocation policy. + */ + public interface Logic { + /** + * Select the node on which the server should be scheduled. + */ + public fun select( + hypervisors: Set<HypervisorView>, + image: SimVirtProvisioningService.ImageView + ): HypervisorView? + } + + /** + * Builds the logic of the policy. + */ + public operator fun invoke(): Logic +} diff --git a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/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 79b622d2..38a07b2b 100644 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/allocation/AvailableCoreMemoryAllocationPolicy.kt +++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/AvailableCoreMemoryAllocationPolicy.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,16 +20,16 @@ * SOFTWARE. */ -package com.atlarge.opendc.compute.virt.service.allocation +package org.opendc.compute.simulator.allocation -import com.atlarge.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. * * @param reversed An option to reverse the order of the machines (lower amount of memory scores better). */ -public class AvailableCoreMemoryAllocationPolicy(val reversed: Boolean = false) : AllocationPolicy { +public class AvailableCoreMemoryAllocationPolicy(private val reversed: Boolean = false) : AllocationPolicy { override fun invoke(): AllocationPolicy.Logic = object : ComparableAllocationPolicyLogic { override val comparator: Comparator<HypervisorView> = compareBy<HypervisorView> { -it.availableMemory / it.server.flavor.cpuCount } diff --git a/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/AvailableMemoryAllocationPolicy.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/AvailableMemoryAllocationPolicy.kt new file mode 100644 index 00000000..e87abd7b --- /dev/null +++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/AvailableMemoryAllocationPolicy.kt @@ -0,0 +1,37 @@ +/* + * 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.allocation + +import org.opendc.compute.simulator.HypervisorView + +/** + * Allocation policy that selects the node with the most available memory. + * + * @param reversed A flag to reverse the order (least amount of memory scores the best). + */ +public class AvailableMemoryAllocationPolicy(public val reversed: Boolean = false) : AllocationPolicy { + override fun invoke(): AllocationPolicy.Logic = object : ComparableAllocationPolicyLogic { + override val comparator: Comparator<HypervisorView> = compareBy<HypervisorView> { -it.availableMemory } + .run { if (reversed) reversed() else this } + } +} diff --git a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/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 79dd95f3..8defe8b7 100644 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/allocation/ComparableAllocationPolicyLogic.kt +++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/ComparableAllocationPolicyLogic.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,16 +20,15 @@ * SOFTWARE. */ -package com.atlarge.opendc.compute.virt.service.allocation +package org.opendc.compute.simulator.allocation -import com.atlarge.opendc.compute.core.image.VmImage -import com.atlarge.opendc.compute.virt.service.HypervisorView -import com.atlarge.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. */ -interface ComparableAllocationPolicyLogic : AllocationPolicy.Logic { +public interface ComparableAllocationPolicyLogic : AllocationPolicy.Logic { /** * The comparator to use. */ @@ -39,14 +36,14 @@ 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/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/NumberOfActiveServersAllocationPolicy.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/NumberOfActiveServersAllocationPolicy.kt new file mode 100644 index 00000000..5e2b895c --- /dev/null +++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/NumberOfActiveServersAllocationPolicy.kt @@ -0,0 +1,37 @@ +/* + * 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.allocation + +import org.opendc.compute.simulator.HypervisorView + +/** + * Allocation policy that selects the node with the least amount of active servers. + * + * @param reversed A flag to reverse the order, such that the node with the most active servers is selected. + */ +public class NumberOfActiveServersAllocationPolicy(public val reversed: Boolean = false) : AllocationPolicy { + override fun invoke(): AllocationPolicy.Logic = object : ComparableAllocationPolicyLogic { + override val comparator: Comparator<HypervisorView> = compareBy<HypervisorView> { it.numberOfActiveServers } + .run { if (reversed) reversed() else this } + } +} diff --git a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/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 e1a995a0..4344d979 100644 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/allocation/ProvisionedCoresAllocationPolicy.kt +++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/ProvisionedCoresAllocationPolicy.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,9 +20,9 @@ * SOFTWARE. */ -package com.atlarge.opendc.compute.virt.service.allocation +package org.opendc.compute.simulator.allocation -import com.atlarge.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 @@ -33,7 +31,7 @@ import com.atlarge.opendc.compute.virt.service.HypervisorView * @param reversed A flag to reverse the order of the policy, such that the machine with the most provisioned cores * is selected. */ -class ProvisionedCoresAllocationPolicy(val reversed: Boolean = false) : AllocationPolicy { +public class ProvisionedCoresAllocationPolicy(private val reversed: Boolean = false) : AllocationPolicy { override fun invoke(): AllocationPolicy.Logic = object : ComparableAllocationPolicyLogic { override val comparator: Comparator<HypervisorView> = compareBy<HypervisorView> { it.provisionedCores / it.server.flavor.cpuCount } diff --git a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/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 07dcf1c5..ac34f410 100644 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/allocation/RandomAllocationPolicy.kt +++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/RandomAllocationPolicy.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,26 +20,25 @@ * SOFTWARE. */ -package com.atlarge.opendc.compute.virt.service.allocation +package org.opendc.compute.simulator.allocation -import com.atlarge.opendc.compute.core.image.VmImage -import com.atlarge.opendc.compute.virt.service.HypervisorView -import com.atlarge.opendc.compute.virt.service.SimpleVirtProvisioningService +import org.opendc.compute.simulator.HypervisorView +import org.opendc.compute.simulator.SimVirtProvisioningService import kotlin.random.Random /** * An [AllocationPolicy] that select a random node on which the server fits. */ -public class RandomAllocationPolicy(val random: Random = Random(0)) : AllocationPolicy { +public class RandomAllocationPolicy(private val random: Random = Random(0)) : AllocationPolicy { @OptIn(ExperimentalStdlibApi::class) 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/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/ReplayAllocationPolicy.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/ReplayAllocationPolicy.kt new file mode 100644 index 00000000..5312f4da --- /dev/null +++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/allocation/ReplayAllocationPolicy.kt @@ -0,0 +1,56 @@ +/* + * 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.allocation + +import mu.KotlinLogging +import org.opendc.compute.simulator.HypervisorView +import org.opendc.compute.simulator.SimVirtProvisioningService + +private val logger = KotlinLogging.logger {} + +/** + * Policy replaying VM-cluster assignment. + * + * Within each cluster, the active servers on each node determine which node gets + * assigned the VM image. + */ +public class ReplayAllocationPolicy(private val vmPlacements: Map<String, String>) : AllocationPolicy { + override fun invoke(): AllocationPolicy.Logic = object : AllocationPolicy.Logic { + override fun select( + hypervisors: Set<HypervisorView>, + image: SimVirtProvisioningService.ImageView + ): HypervisorView? { + val clusterName = vmPlacements[image.name] + ?: throw IllegalStateException("Could not find placement data in VM placement file for VM ${image.name}") + val machinesInCluster = hypervisors.filter { it.server.name.contains(clusterName) } + + if (machinesInCluster.isEmpty()) { + logger.info { "Could not find any machines belonging to cluster $clusterName for image ${image.name}, assigning randomly." } + return hypervisors.maxByOrNull { it.availableMemory } + } + + return machinesInCluster.maxByOrNull { it.availableMemory } + ?: throw IllegalStateException("Cloud not find any machine and could not randomly assign") + } + } +} diff --git a/simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/power/PowerModel.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/power/PowerModel.kt index 51c9f379..174a510b 100644 --- a/simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/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 com.atlarge.opendc.core.power +package org.opendc.compute.simulator.power import kotlinx.coroutines.flow.Flow diff --git a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/metal/power/PowerModels.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/power/PowerModels.kt index 9ddbe08e..651eba6e 100644 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/metal/power/PowerModels.kt +++ b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/power/PowerModels.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,12 +20,11 @@ * SOFTWARE. */ -package com.atlarge.opendc.compute.metal.power +package org.opendc.compute.simulator.power -import com.atlarge.opendc.compute.metal.driver.BareMetalDriver -import com.atlarge.opendc.core.power.PowerModel import kotlinx.coroutines.flow.flowOf import kotlinx.coroutines.flow.map +import org.opendc.compute.core.metal.driver.BareMetalDriver /** * A power model which emits a single value. diff --git a/simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/power/Powerable.kt b/simulator/opendc-compute/opendc-compute-simulator/src/main/kotlin/org/opendc/compute/simulator/power/Powerable.kt index 4473a571..dcf74468 100644 --- a/simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/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 com.atlarge.opendc.core.power +package org.opendc.compute.simulator.power import kotlinx.coroutines.flow.Flow @@ -33,5 +33,5 @@ public interface Powerable { /** * The power draw at the device's power supply in watts (W).w */ - val powerDraw: Flow<Double> + public val powerDraw: Flow<Double> } diff --git a/simulator/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/metal/driver/SimpleBareMetalDriverTest.kt b/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimBareMetalDriverTest.kt index af9d3421..0f1bd444 100644 --- a/simulator/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/metal/driver/SimpleBareMetalDriverTest.kt +++ b/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimBareMetalDriverTest.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,67 +20,70 @@ * SOFTWARE. */ -package com.atlarge.opendc.compute.metal.driver +package org.opendc.compute.simulator -import com.atlarge.odcsim.SimulationEngineProvider -import com.atlarge.odcsim.simulationContext -import com.atlarge.opendc.compute.core.ProcessingNode -import com.atlarge.opendc.compute.core.ProcessingUnit -import com.atlarge.opendc.compute.core.ServerEvent -import com.atlarge.opendc.compute.core.ServerState -import com.atlarge.opendc.compute.core.image.FlopsApplicationImage -import java.util.ServiceLoader -import java.util.UUID +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.runBlocking +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.ServerEvent +import org.opendc.compute.core.ServerState +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 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) } + ) + } -internal class SimpleBareMetalDriverTest { - /** - * A smoke test for the bare-metal driver. - */ @Test - fun smoke() { + fun testFlopsWorkload() { + val testScope = TestCoroutineScope() + val clock = DelayControllerClockAdapter(testScope) + var finalState: ServerState = ServerState.BUILD - val provider = ServiceLoader.load(SimulationEngineProvider::class.java).first() - val system = provider("sim") - val root = system.newDomain(name = "root") - root.launch { - val dom = root.newDomain(name = "driver") - val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 4) - val cpus = List(4) { ProcessingUnit(cpuNode, it, 2400.0) } - val driver = SimpleBareMetalDriver(dom, UUID.randomUUID(), "test", emptyMap(), cpus, emptyList()) - val image = FlopsApplicationImage(UUID.randomUUID(), "<unnamed>", emptyMap(), 1_000, 2) + var finalTime = 0L + + testScope.launch { + 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(dom.coroutineContext) { + withContext(coroutineContext) { driver.init() driver.setImage(image) val server = driver.start().server!! - driver.usage - .onEach { println("${simulationContext.clock.millis()} $it") } - .launchIn(this) server.events.collect { event -> when (event) { is ServerEvent.StateChanged -> { - println("${simulationContext.clock.millis()} $event") finalState = event.server.state + finalTime = clock.millis() } } } } } - runBlocking { - system.run() - system.terminate() - } - + testScope.advanceUntilIdle() assertEquals(ServerState.SHUTOFF, finalState) + assertEquals(1001, finalTime) } } diff --git a/simulator/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/metal/service/SimpleProvisioningServiceTest.kt b/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimProvisioningServiceTest.kt index ed2256c0..def78ce7 100644 --- a/simulator/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/metal/service/SimpleProvisioningServiceTest.kt +++ b/simulator/opendc-compute/opendc-compute-simulator/src/test/kotlin/org/opendc/compute/simulator/SimProvisioningServiceTest.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,42 +20,54 @@ * SOFTWARE. */ -package com.atlarge.opendc.compute.metal.service +package org.opendc.compute.simulator -import com.atlarge.odcsim.SimulationEngineProvider -import com.atlarge.opendc.compute.core.ProcessingNode -import com.atlarge.opendc.compute.core.ProcessingUnit -import com.atlarge.opendc.compute.core.image.FlopsApplicationImage -import com.atlarge.opendc.compute.metal.driver.SimpleBareMetalDriver -import java.util.ServiceLoader -import java.util.UUID +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.delay import kotlinx.coroutines.flow.collect import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.TestCoroutineScope +import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test +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 /** * Test suite for the [SimpleProvisioningService]. */ -internal class SimpleProvisioningServiceTest { +@OptIn(ExperimentalCoroutinesApi::class) +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() { - val provider = ServiceLoader.load(SimulationEngineProvider::class.java).first() - val system = provider("sim") - val root = system.newDomain(name = "root") - root.launch { - val image = FlopsApplicationImage(UUID.randomUUID(), "<unnamed>", emptyMap(), 1000, 2) - val dom = root.newDomain("provisioner") + fun testSmoke() { + val testScope = TestCoroutineScope() + val clock = DelayControllerClockAdapter(testScope) - val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 4) - val cpus = List(4) { ProcessingUnit(cpuNode, it, 2400.0) } - val driver = SimpleBareMetalDriver(dom.newDomain(), UUID.randomUUID(), "test", emptyMap(), cpus, emptyList()) + testScope.launch { + val image = SimWorkloadImage(UUID.randomUUID(), "<unnamed>", emptyMap(), SimFlopsWorkload(1000, 2)) + val driver = SimBareMetalDriver(this, clock, UUID.randomUUID(), "test", emptyMap(), machineModel) - val provisioner = SimpleProvisioningService(dom) + val provisioner = SimpleProvisioningService() provisioner.create(driver) delay(5) val nodes = provisioner.nodes() @@ -65,9 +75,6 @@ internal class SimpleProvisioningServiceTest { node.server!!.events.collect { println(it) } } - runBlocking { - system.run() - system.terminate() - } + testScope.advanceUntilIdle() } } 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/opendc-core/build.gradle.kts b/simulator/opendc-core/build.gradle.kts index 5443f056..b1c2678b 100644 --- a/simulator/opendc/opendc-core/build.gradle.kts +++ b/simulator/opendc-core/build.gradle.kts @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2017 atlarge-research + * Copyright (c) 2017 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. */ -description = "Base model for topology simulation" +description = "Base model for datacenter simulation" /* Build configuration */ plugins { @@ -30,8 +28,7 @@ plugins { } dependencies { - implementation(kotlin("stdlib")) - api(project(":odcsim:odcsim-api")) + api("org.jetbrains.kotlinx:kotlinx-coroutines-core:${Library.KOTLINX_COROUTINES}") 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/opendc-core/src/main/kotlin/com/atlarge/opendc/core/Environment.kt b/simulator/opendc-core/src/main/kotlin/org/opendc/core/Environment.kt index 62309bf9..a5055cff 100644 --- a/simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/Environment.kt +++ b/simulator/opendc-core/src/main/kotlin/org/opendc/core/Environment.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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 com.atlarge.opendc.core +package org.opendc.core /** * A description of a large-scale computing environment. This description includes including key size and topology @@ -33,4 +31,4 @@ package com.atlarge.opendc.core * @property description A small textual description about the environment that is being modeled. * @property platforms The cloud platforms (such as AWS or GCE) in this environment. */ -data class Environment(val name: String, val description: String?, val platforms: List<Platform>) +public data class Environment(val name: String, val description: String?, val platforms: List<Platform>) diff --git a/simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/Identity.kt b/simulator/opendc-core/src/main/kotlin/org/opendc/core/Identity.kt index c87e934f..252c40f5 100644 --- a/simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/Identity.kt +++ b/simulator/opendc-core/src/main/kotlin/org/opendc/core/Identity.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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,21 +20,21 @@ * SOFTWARE. */ -package com.atlarge.opendc.core +package org.opendc.core -import java.util.UUID +import java.util.* /** * An object that has a unique identity. */ -interface Identity { +public interface Identity { /** * A unique, opaque, system-generated value, representing the object. */ - val uid: UUID + public val uid: UUID /** * A non-empty, human-readable string representing the object. */ - val name: String + public val name: String } diff --git a/simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/Platform.kt b/simulator/opendc-core/src/main/kotlin/org/opendc/core/Platform.kt index 0b2437c6..5550ffed 100644 --- a/simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/Platform.kt +++ b/simulator/opendc-core/src/main/kotlin/org/opendc/core/Platform.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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,9 +20,9 @@ * SOFTWARE. */ -package com.atlarge.opendc.core +package org.opendc.core -import java.util.UUID +import java.util.* /** * A representation of a cloud platform such as Amazon Web Services (AWS), Microsoft Azure or Google Cloud. @@ -33,4 +31,4 @@ import java.util.UUID * @property name the name of the platform. * @property zones The availability zones available on this platform. */ -data class Platform(override val uid: UUID, override val name: String, val zones: List<Zone>) : Identity +public data class Platform(override val uid: UUID, override val name: String, val zones: List<Zone>) : Identity diff --git a/simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/User.kt b/simulator/opendc-core/src/main/kotlin/org/opendc/core/User.kt index 6105ae9e..fc542cef 100644 --- a/simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/User.kt +++ b/simulator/opendc-core/src/main/kotlin/org/opendc/core/User.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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,12 +20,12 @@ * SOFTWARE. */ -package com.atlarge.opendc.core +package org.opendc.core /** * A user of the cloud network. */ -interface User : Identity { +public interface User : Identity { /** * The name of the user. */ diff --git a/simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/Zone.kt b/simulator/opendc-core/src/main/kotlin/org/opendc/core/Zone.kt index d8851bcd..834f6cf2 100644 --- a/simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/Zone.kt +++ b/simulator/opendc-core/src/main/kotlin/org/opendc/core/Zone.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,10 +20,10 @@ * SOFTWARE. */ -package com.atlarge.opendc.core +package org.opendc.core -import com.atlarge.opendc.core.services.ServiceRegistry -import java.util.UUID +import org.opendc.core.services.ServiceRegistry +import java.util.* /** * An isolated location within a topology region from which public cloud services operate, roughly equivalent to a @@ -38,7 +36,7 @@ import java.util.UUID * @property name The name of the zone within its platform. * @property services The service registry containing the services of the zone. */ -data class Zone( +public data class Zone( override val uid: UUID, override val name: String, val services: ServiceRegistry diff --git a/simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/resource/Resource.kt b/simulator/opendc-core/src/main/kotlin/org/opendc/core/resource/Resource.kt index 25a494bc..5bb2c2ce 100644 --- a/simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/resource/Resource.kt +++ b/simulator/opendc-core/src/main/kotlin/org/opendc/core/resource/Resource.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,9 +20,9 @@ * SOFTWARE. */ -package com.atlarge.opendc.core.resource +package org.opendc.core.resource -import com.atlarge.opendc.core.Identity +import org.opendc.core.Identity /** * Represents a generic cloud resource. diff --git a/simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/resource/TagContainer.kt b/simulator/opendc-core/src/main/kotlin/org/opendc/core/resource/TagContainer.kt index 6ba1cf0b..6a4ff102 100644 --- a/simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/resource/TagContainer.kt +++ b/simulator/opendc-core/src/main/kotlin/org/opendc/core/resource/TagContainer.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,15 +20,15 @@ * SOFTWARE. */ -package com.atlarge.opendc.core.resource +package org.opendc.core.resource /** * An immutable map containing the tags of some resource. */ -typealias TagContainer = Map<String, Any> +public typealias TagContainer = Map<String, Any> /** * Obtain the value of the tag with the specified [key] of type [T]. If the tag does not exist or the tag is of * different type, `null` is returned. */ -inline fun <reified T : Any> TagContainer.typed(key: String): T? = this[key] as? T +public inline fun <reified T : Any> TagContainer.typed(key: String): T? = this[key] as? T diff --git a/simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/services/ServiceKey.kt b/simulator/opendc-core/src/main/kotlin/org/opendc/core/services/ServiceKey.kt index 290bf439..9078ecdd 100644 --- a/simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/services/ServiceKey.kt +++ b/simulator/opendc-core/src/main/kotlin/org/opendc/core/services/ServiceKey.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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,17 +20,17 @@ * SOFTWARE. */ -package com.atlarge.opendc.core.services +package org.opendc.core.services -import com.atlarge.opendc.core.Identity -import java.util.UUID +import org.opendc.core.Identity +import java.util.* /** * An interface for identifying service implementations of the same type (providing the same service). * * @param T The shape of the messages the service responds to. */ -interface ServiceKey<T : Any> : Identity +public interface ServiceKey<T : Any> : Identity /** * Helper class for constructing a [ServiceKey]. @@ -40,7 +38,7 @@ interface ServiceKey<T : Any> : Identity * @property uid The unique identifier of the service. * @property name The name of the service. */ -abstract class AbstractServiceKey<T : Any>(override val uid: UUID, override val name: String) : ServiceKey<T> { +public abstract class AbstractServiceKey<T : Any>(override val uid: UUID, override val name: String) : ServiceKey<T> { override fun equals(other: Any?): Boolean = other is ServiceKey<*> && uid == other.uid override fun hashCode(): Int = uid.hashCode() override fun toString(): String = "ServiceKey[uid=$uid, name=$name]" diff --git a/simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/services/ServiceRegistry.kt b/simulator/opendc-core/src/main/kotlin/org/opendc/core/services/ServiceRegistry.kt index 75aa778f..7434d91c 100644 --- a/simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/services/ServiceRegistry.kt +++ b/simulator/opendc-core/src/main/kotlin/org/opendc/core/services/ServiceRegistry.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 com.atlarge.opendc.core.services +package org.opendc.core.services /** * An immutable service registry interface. diff --git a/simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/services/ServiceRegistryImpl.kt b/simulator/opendc-core/src/main/kotlin/org/opendc/core/services/ServiceRegistryImpl.kt index 0686ebaf..e117bec6 100644 --- a/simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/services/ServiceRegistryImpl.kt +++ b/simulator/opendc-core/src/main/kotlin/org/opendc/core/services/ServiceRegistryImpl.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 com.atlarge.opendc.core.services +package org.opendc.core.services /** * Default implementation of the [ServiceRegistry] interface. @@ -38,7 +36,8 @@ internal class ServiceRegistryImpl(private val map: Map<ServiceKey<*>, Any>) : S return map[key] as T } - override fun <T : Any> put(key: ServiceKey<T>, service: T): ServiceRegistry = ServiceRegistryImpl(map.plus(key to service)) + override fun <T : Any> put(key: ServiceKey<T>, service: T): ServiceRegistry = + ServiceRegistryImpl(map.plus(key to service)) override fun toString(): String = map.toString() } diff --git a/simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/workload/Workload.kt b/simulator/opendc-core/src/main/kotlin/org/opendc/core/workload/Workload.kt index def5d6e4..f0bd1137 100644 --- a/simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/workload/Workload.kt +++ b/simulator/opendc-core/src/main/kotlin/org/opendc/core/workload/Workload.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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,18 +20,18 @@ * SOFTWARE. */ -package com.atlarge.opendc.core.workload +package org.opendc.core.workload -import com.atlarge.opendc.core.Identity -import com.atlarge.opendc.core.User +import org.opendc.core.Identity +import org.opendc.core.User /** * A high-level abstraction that represents the actual work that a set of compute resources perform, such * as running an application on a machine or a whole workflow running multiple tasks on numerous machines. */ -interface Workload : Identity { +public interface Workload : Identity { /** * The owner of this workload. */ - val owner: User + public val owner: User } diff --git a/simulator/odcsim/build.gradle.kts b/simulator/opendc-experiments/build.gradle.kts index cc3f3add..a1a751a2 100644 --- a/simulator/odcsim/build.gradle.kts +++ b/simulator/opendc-experiments/build.gradle.kts @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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 diff --git a/simulator/opendc/opendc-experiments-sc18/build.gradle.kts b/simulator/opendc-experiments/opendc-experiments-sc18/build.gradle.kts index 2e366a43..9cf72f18 100644 --- a/simulator/opendc/opendc-experiments-sc18/build.gradle.kts +++ b/simulator/opendc-experiments/opendc-experiments-sc18/build.gradle.kts @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 atlarge-research + * Copyright (c) 2019 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 @@ -31,16 +29,19 @@ plugins { } application { - mainClassName = "com.atlarge.opendc.experiments.sc18.TestExperiment" + mainClassName = "org.opendc.experiments.sc18.TestExperiment" } dependencies { - api(project(":opendc:opendc-core")) - implementation(project(":opendc:opendc-format")) - implementation(project(":opendc:opendc-workflows")) - implementation(kotlin("stdlib")) + api(project(":opendc-core")) + implementation(project(":opendc-format")) + implementation(project(":opendc-workflows")) + 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")) - runtimeOnly(project(":odcsim:odcsim-engine-omega")) 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/opendc-experiments-sc18/src/main/kotlin/com/atlarge/opendc/experiments/sc18/TestExperiment.kt b/simulator/opendc-experiments/opendc-experiments-sc18/src/main/kotlin/org/opendc/experiments/sc18/TestExperiment.kt index 7659b18e..3786eebf 100644 --- a/simulator/opendc/opendc-experiments-sc18/src/main/kotlin/com/atlarge/opendc/experiments/sc18/TestExperiment.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc18/src/main/kotlin/org/opendc/experiments/sc18/TestExperiment.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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,37 +20,34 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc18 +package org.opendc.experiments.sc18 -import com.atlarge.odcsim.SimulationEngineProvider -import com.atlarge.odcsim.simulationContext -import com.atlarge.opendc.compute.metal.service.ProvisioningService -import com.atlarge.opendc.format.environment.sc18.Sc18EnvironmentReader -import com.atlarge.opendc.format.trace.gwf.GwfTraceReader -import com.atlarge.opendc.workflows.service.StageWorkflowService -import com.atlarge.opendc.workflows.service.WorkflowEvent -import com.atlarge.opendc.workflows.service.WorkflowSchedulerMode -import com.atlarge.opendc.workflows.service.stage.job.NullJobAdmissionPolicy -import com.atlarge.opendc.workflows.service.stage.job.SubmissionTimeJobOrderPolicy -import com.atlarge.opendc.workflows.service.stage.resource.FirstFitResourceSelectionPolicy -import com.atlarge.opendc.workflows.service.stage.resource.FunctionalResourceFilterPolicy -import com.atlarge.opendc.workflows.service.stage.task.NullTaskEligibilityPolicy -import com.atlarge.opendc.workflows.service.stage.task.SubmissionTimeTaskOrderPolicy -import java.io.File -import java.util.ServiceLoader -import kotlin.math.max -import kotlinx.coroutines.async +import kotlinx.coroutines.* import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.delay import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.TestCoroutineScope +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 +import org.opendc.workflows.service.StageWorkflowService +import org.opendc.workflows.service.WorkflowEvent +import org.opendc.workflows.service.WorkflowSchedulerMode +import org.opendc.workflows.service.stage.job.NullJobAdmissionPolicy +import org.opendc.workflows.service.stage.job.SubmissionTimeJobOrderPolicy +import org.opendc.workflows.service.stage.resource.FirstFitResourceSelectionPolicy +import org.opendc.workflows.service.stage.resource.FunctionalResourceFilterPolicy +import org.opendc.workflows.service.stage.task.NullTaskEligibilityPolicy +import org.opendc.workflows.service.stage.task.SubmissionTimeTaskOrderPolicy +import java.io.File +import kotlin.math.max /** * Main entry point of the experiment. */ -fun main(args: Array<String>) { +@OptIn(ExperimentalCoroutinesApi::class) +public fun main(args: Array<String>) { if (args.isEmpty()) { println("error: Please provide path to GWF trace") return @@ -62,16 +57,16 @@ fun main(args: Array<String>) { var finished = 0 val token = Channel<Boolean>() - val provider = ServiceLoader.load(SimulationEngineProvider::class.java).first() - val system = provider(name = "sim") + val testScope = TestCoroutineScope() + val clock = DelayControllerClockAdapter(testScope) - val schedulerDomain = system.newDomain(name = "scheduler") - val schedulerAsync = schedulerDomain.async { + val schedulerAsync = testScope.async { val environment = Sc18EnvironmentReader(object {}.javaClass.getResourceAsStream("/env/setup-test.json")) - .use { it.construct(system.newDomain("topology")) } + .use { it.construct(this, clock) } StageWorkflowService( - schedulerDomain, + this, + clock, environment.platforms[0].zones[0].services[ProvisioningService], mode = WorkflowSchedulerMode.Batch(100), jobAdmissionPolicy = NullJobAdmissionPolicy, @@ -83,9 +78,7 @@ fun main(args: Array<String>) { ) } - val broker = system.newDomain(name = "broker") - - broker.launch { + testScope.launch { val scheduler = schedulerAsync.await() scheduler.events .onEach { event -> @@ -105,21 +98,18 @@ fun main(args: Array<String>) { } .collect() } - broker.launch { - val ctx = simulationContext + + testScope.launch { val reader = GwfTraceReader(File(args[0])) val scheduler = schedulerAsync.await() while (reader.hasNext()) { val (time, job) = reader.next() total += 1 - delay(max(0, time * 1000 - ctx.clock.millis())) + delay(max(0, time * 1000 - clock.millis())) scheduler.submit(job) } } - runBlocking { - system.run() - system.terminate() - } + testScope.advanceUntilIdle() } diff --git a/simulator/opendc/opendc-experiments-sc18/src/main/resources/env/setup-test.json b/simulator/opendc-experiments/opendc-experiments-sc18/src/main/resources/env/setup-test.json index 0965b250..0965b250 100644 --- a/simulator/opendc/opendc-experiments-sc18/src/main/resources/env/setup-test.json +++ b/simulator/opendc-experiments/opendc-experiments-sc18/src/main/resources/env/setup-test.json diff --git a/simulator/opendc/opendc-experiments-sc20/build.gradle.kts b/simulator/opendc-experiments/opendc-experiments-sc20/build.gradle.kts index 46d99564..3b682668 100644 --- a/simulator/opendc/opendc-experiments-sc20/build.gradle.kts +++ b/simulator/opendc-experiments/opendc-experiments-sc20/build.gradle.kts @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 atlarge-research + * Copyright (c) 2019 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 @@ -31,14 +29,17 @@ plugins { } application { - mainClassName = "com.atlarge.opendc.experiments.sc20.MainKt" + mainClassName = "org.opendc.experiments.sc20.MainKt" applicationDefaultJvmArgs = listOf("-Xms2500M") } dependencies { - api(project(":opendc:opendc-core")) - implementation(project(":opendc:opendc-format")) - implementation(kotlin("stdlib")) + api(project(":opendc-core")) + implementation(project(":opendc-format")) + 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") @@ -51,7 +52,6 @@ dependencies { } runtimeOnly("org.apache.logging.log4j:log4j-slf4j-impl:2.13.1") - runtimeOnly(project(":odcsim:odcsim-engine-omega")) 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/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/Main.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/Main.kt index 4781f335..8916261b 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/Main.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/Main.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,15 +20,8 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20 +package org.opendc.experiments.sc20 -import com.atlarge.opendc.experiments.sc20.experiment.* -import com.atlarge.opendc.experiments.sc20.reporter.ConsoleExperimentReporter -import com.atlarge.opendc.experiments.sc20.runner.ExperimentDescriptor -import com.atlarge.opendc.experiments.sc20.runner.execution.ThreadPoolExperimentScheduler -import com.atlarge.opendc.experiments.sc20.runner.internal.DefaultExperimentRunner -import com.atlarge.opendc.format.trace.sc20.Sc20PerformanceInterferenceReader -import com.atlarge.opendc.format.trace.sc20.Sc20VmPlacementReader import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.parameters.options.convert import com.github.ajalt.clikt.parameters.options.default @@ -41,9 +32,15 @@ import com.github.ajalt.clikt.parameters.options.required import com.github.ajalt.clikt.parameters.types.choice import com.github.ajalt.clikt.parameters.types.file import com.github.ajalt.clikt.parameters.types.int -import java.io.File -import java.io.InputStream import mu.KotlinLogging +import org.opendc.experiments.sc20.experiment.* +import org.opendc.experiments.sc20.reporter.ConsoleExperimentReporter +import org.opendc.experiments.sc20.runner.ExperimentDescriptor +import org.opendc.experiments.sc20.runner.execution.ThreadPoolExperimentScheduler +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 /** * The logger for this experiment. @@ -53,7 +50,7 @@ private val logger = KotlinLogging.logger {} /** * Represents the command for running the experiment. */ -class ExperimentCli : CliktCommand(name = "sc20-experiment") { +public class ExperimentCli : CliktCommand(name = "sc20-experiment") { /** * The path to the directory where the topology descriptions are located. */ @@ -71,15 +68,18 @@ class ExperimentCli : CliktCommand(name = "sc20-experiment") { /** * The path to the performance interference model. */ - private val performanceInterferenceStream by option("--performance-interference-model", help = "path to the performance interference file") - .file() - .convert { it.inputStream() as InputStream } + private val performanceInterferenceStream by option( + "--performance-interference-model", + help = "path to the performance interference file" + ) + .file(canBeDir = false) + .convert { it.inputStream() } /** * The path to the original VM placements file. */ private val vmPlacements by option("--vm-placements-file", help = "path to the VM placement file") - .file() + .file(canBeDir = false) .convert { Sc20VmPlacementReader(it.inputStream().buffered()).construct() } @@ -88,7 +88,7 @@ class ExperimentCli : CliktCommand(name = "sc20-experiment") { /** * The selected portfolios to run. */ - private val portfolios by option("--portfolio") + private val portfolios by option("--portfolio", help = "portfolio of scenarios to explore") .choice( "hor-ver" to { experiment: Experiment, i: Int -> HorVerPortfolio(experiment, i) } as (Experiment, Int) -> Portfolio, @@ -100,12 +100,12 @@ class ExperimentCli : CliktCommand(name = "sc20-experiment") { "more-hpc" to { experiment, i -> MoreHpcPortfolio(experiment, i) }, ignoreCase = true ) - .multiple() + .multiple(required = true) /** * The maximum number of worker threads to use. */ - private val parallelism by option("--parallelism") + private val parallelism by option("--parallelism", help = "maximum number of concurrent simulation runs") .int() .default(Runtime.getRuntime().availableProcessors()) @@ -130,7 +130,8 @@ class ExperimentCli : CliktCommand(name = "sc20-experiment") { performanceInterferenceStream?.let { Sc20PerformanceInterferenceReader(it) } logger.info { "Creating experiment descriptor" } - val descriptor = object : Experiment(environmentPath, tracePath, output, performanceInterferenceModel, vmPlacements, bufferSize) { + val descriptor = object : + Experiment(environmentPath, tracePath, output, performanceInterferenceModel, vmPlacements, bufferSize) { private val descriptor = this override val children: Sequence<ExperimentDescriptor> = sequence { for ((i, producer) in portfolios.withIndex()) { @@ -142,10 +143,12 @@ class ExperimentCli : CliktCommand(name = "sc20-experiment") { logger.info { "Starting experiment runner [parallelism=$parallelism]" } val scheduler = ThreadPoolExperimentScheduler(parallelism) val runner = DefaultExperimentRunner(scheduler) + val reporter = ConsoleExperimentReporter() try { - runner.execute(descriptor, ConsoleExperimentReporter()) + runner.execute(descriptor, reporter) } finally { scheduler.close() + reporter.close() } } } @@ -153,4 +156,4 @@ class ExperimentCli : CliktCommand(name = "sc20-experiment") { /** * Main entry point of the experiment. */ -fun main(args: Array<String>) = ExperimentCli().main(args) +public fun main(args: Array<String>): Unit = ExperimentCli().main(args) diff --git a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/experiment/Experiment.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/Experiment.kt index f3ac2554..34d7301b 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/experiment/Experiment.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/Experiment.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,15 +20,15 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.experiment +package org.opendc.experiments.sc20.experiment -import com.atlarge.opendc.experiments.sc20.runner.ContainerExperimentDescriptor -import com.atlarge.opendc.experiments.sc20.runner.ExperimentDescriptor -import com.atlarge.opendc.experiments.sc20.runner.execution.ExperimentExecutionContext -import com.atlarge.opendc.experiments.sc20.runner.execution.ExperimentExecutionListener -import com.atlarge.opendc.experiments.sc20.telemetry.RunEvent -import com.atlarge.opendc.experiments.sc20.telemetry.parquet.ParquetRunEventWriter -import com.atlarge.opendc.format.trace.PerformanceInterferenceModelReader +import org.opendc.experiments.sc20.runner.ContainerExperimentDescriptor +import org.opendc.experiments.sc20.runner.ExperimentDescriptor +import org.opendc.experiments.sc20.runner.execution.ExperimentExecutionContext +import org.opendc.experiments.sc20.runner.execution.ExperimentExecutionListener +import org.opendc.experiments.sc20.telemetry.RunEvent +import org.opendc.experiments.sc20.telemetry.parquet.ParquetRunEventWriter +import org.opendc.format.trace.PerformanceInterferenceModelReader import java.io.File /** @@ -44,12 +42,12 @@ import java.io.File * @param bufferSize The buffer size of the event reporters. */ public abstract class Experiment( - val environments: File, - val traces: File, - val output: File, - val performanceInterferenceModel: PerformanceInterferenceModelReader?, - val vmPlacements: Map<String, String>, - val bufferSize: Int + public val environments: File, + public val traces: File, + public val output: File, + public val performanceInterferenceModel: PerformanceInterferenceModelReader?, + public val vmPlacements: Map<String, String>, + public val bufferSize: Int ) : ContainerExperimentDescriptor() { override val parent: ExperimentDescriptor? = null diff --git a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/experiment/ExperimentHelpers.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/ExperimentHelpers.kt index b09c0dbb..09f44199 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/experiment/ExperimentHelpers.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/ExperimentHelpers.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,33 +20,9 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.experiment - -import com.atlarge.odcsim.Domain -import com.atlarge.odcsim.simulationContext -import com.atlarge.opendc.compute.core.Flavor -import com.atlarge.opendc.compute.core.ServerEvent -import com.atlarge.opendc.compute.core.workload.PerformanceInterferenceModel -import com.atlarge.opendc.compute.core.workload.VmWorkload -import com.atlarge.opendc.compute.metal.NODE_CLUSTER -import com.atlarge.opendc.compute.metal.driver.BareMetalDriver -import com.atlarge.opendc.compute.metal.service.ProvisioningService -import com.atlarge.opendc.compute.virt.HypervisorEvent -import com.atlarge.opendc.compute.virt.driver.SimpleVirtDriver -import com.atlarge.opendc.compute.virt.service.SimpleVirtProvisioningService -import com.atlarge.opendc.compute.virt.service.VirtProvisioningEvent -import com.atlarge.opendc.compute.virt.service.allocation.AllocationPolicy -import com.atlarge.opendc.core.failure.CorrelatedFaultInjector -import com.atlarge.opendc.core.failure.FailureDomain -import com.atlarge.opendc.core.failure.FaultInjector -import com.atlarge.opendc.experiments.sc20.experiment.monitor.ExperimentMonitor -import com.atlarge.opendc.experiments.sc20.trace.Sc20StreamingParquetTraceReader -import com.atlarge.opendc.format.environment.EnvironmentReader -import com.atlarge.opendc.format.trace.TraceReader -import java.io.File -import kotlin.math.ln -import kotlin.math.max -import kotlin.random.Random +package org.opendc.experiments.sc20.experiment + +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.delay @@ -57,8 +31,32 @@ import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.flow.takeWhile import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext import mu.KotlinLogging +import org.opendc.compute.core.Flavor +import org.opendc.compute.core.ServerEvent +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.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 +import kotlin.math.max +import kotlin.random.Random /** * The logger for this experiment. @@ -68,15 +66,15 @@ private val logger = KotlinLogging.logger {} /** * Construct the failure domain for the experiments. */ -suspend fun createFailureDomain( +public suspend fun createFailureDomain( + coroutineScope: CoroutineScope, + clock: Clock, seed: Int, failureInterval: Double, bareMetalProvisioner: ProvisioningService, chan: Channel<Unit> -): Domain { - val root = simulationContext.domain - val domain = root.newDomain(name = "failures") - domain.launch { +): CoroutineScope { + val job = coroutineScope.launch { chan.receive() val random = Random(seed) val injectors = mutableMapOf<String, FaultInjector>() @@ -85,7 +83,8 @@ suspend fun createFailureDomain( val injector = injectors.getOrPut(cluster) { createFaultInjector( - simulationContext.domain, + this, + clock, random, failureInterval ) @@ -93,17 +92,23 @@ suspend fun createFailureDomain( injector.enqueue(node.metadata["driver"] as FailureDomain) } } - return domain + return CoroutineScope(coroutineScope.coroutineContext + job) } /** * Obtain the [FaultInjector] to use for the experiments. */ -fun createFaultInjector(domain: Domain, random: Random, failureInterval: Double): FaultInjector { +public fun createFaultInjector( + coroutineScope: CoroutineScope, + clock: Clock, + random: Random, + failureInterval: Double +): FaultInjector { // Parameters from A. Iosup, A Framework for the Study of Grid Inter-Operation Mechanisms, 2009 // GRID'5000 return CorrelatedFaultInjector( - domain, + coroutineScope, + clock, iatScale = ln(failureInterval), iatShape = 1.03, // Hours sizeScale = ln(2.0), sizeShape = ln(1.0), // Expect 2 machines, with variation of 1 dScale = ln(60.0), dShape = ln(60.0 * 8), // Minutes @@ -114,7 +119,12 @@ fun createFaultInjector(domain: Domain, random: Random, failureInterval: Double) /** * Create the trace reader from which the VM workloads are read. */ -fun createTraceReader(path: File, performanceInterferenceModel: PerformanceInterferenceModel, vms: List<String>, seed: Int): Sc20StreamingParquetTraceReader { +public fun createTraceReader( + path: File, + performanceInterferenceModel: PerformanceInterferenceModel, + vms: List<String>, + seed: Int +): Sc20StreamingParquetTraceReader { return Sc20StreamingParquetTraceReader( path, performanceInterferenceModel, @@ -126,39 +136,45 @@ fun createTraceReader(path: File, performanceInterferenceModel: PerformanceInter /** * Construct the environment for a VM provisioner and return the provisioner instance. */ -suspend fun createProvisioner( - root: Domain, +public suspend fun createProvisioner( + coroutineScope: CoroutineScope, + clock: Clock, environmentReader: EnvironmentReader, allocationPolicy: AllocationPolicy -): Pair<ProvisioningService, SimpleVirtProvisioningService> = withContext(root.coroutineContext) { - val environment = environmentReader.use { it.construct(root) } +): 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(allocationPolicy, simulationContext, bareMetalProvisioner) + val scheduler = SimVirtProvisioningService(coroutineScope, clock, bareMetalProvisioner, allocationPolicy) // Wait for the hypervisors to be spawned delay(10) - bareMetalProvisioner to scheduler + return bareMetalProvisioner to scheduler } /** * Attach the specified monitor to the VM provisioner. */ @OptIn(ExperimentalCoroutinesApi::class) -suspend fun attachMonitor(scheduler: SimpleVirtProvisioningService, monitor: ExperimentMonitor) { - val domain = simulationContext.domain - val clock = simulationContext.clock +public suspend fun attachMonitor( + coroutineScope: CoroutineScope, + clock: Clock, + scheduler: SimVirtProvisioningService, + monitor: ExperimentMonitor +) { + val hypervisors = scheduler.drivers() // 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) { @@ -167,7 +183,7 @@ suspend fun attachMonitor(scheduler: SimpleVirtProvisioningService, monitor: Exp } } } - .launchIn(domain) + .launchIn(coroutineScope) hypervisor.events .onEach { event -> when (event) { @@ -184,12 +200,12 @@ suspend fun attachMonitor(scheduler: SimpleVirtProvisioningService, monitor: Exp ) } } - .launchIn(domain) + .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(domain) + .launchIn(coroutineScope) } scheduler.events @@ -199,15 +215,20 @@ suspend fun attachMonitor(scheduler: SimpleVirtProvisioningService, monitor: Exp monitor.reportProvisionerMetrics(clock.millis(), event) } } - .launchIn(domain) + .launchIn(coroutineScope) } /** * Process the trace. */ -suspend fun processTrace(reader: TraceReader<VmWorkload>, scheduler: SimpleVirtProvisioningService, chan: Channel<Unit>, monitor: ExperimentMonitor, vmPlacements: Map<String, String> = emptyMap()) { - val domain = simulationContext.domain - +public suspend fun processTrace( + coroutineScope: CoroutineScope, + clock: Clock, + reader: TraceReader<VmWorkload>, + scheduler: SimVirtProvisioningService, + chan: Channel<Unit>, + monitor: ExperimentMonitor +) { try { var submitted = 0 @@ -215,18 +236,22 @@ suspend fun processTrace(reader: TraceReader<VmWorkload>, scheduler: SimpleVirtP val (time, workload) = reader.next() submitted++ - delay(max(0, time - simulationContext.clock.millis())) - domain.launch { + delay(max(0, time - clock.millis())) + coroutineScope.launch { chan.send(Unit) val server = scheduler.deploy( - workload.image.name, workload.image, - Flavor(workload.image.maxCores, workload.image.requiredMemory) + workload.image.name, + workload.image, + Flavor( + workload.image.tags["cores"] as Int, + workload.image.tags["required-memory"] as Long + ) ) // Monitor server events server.events .onEach { if (it is ServerEvent.StateChanged) { - monitor.reportVmStateChange(simulationContext.clock.millis(), it.server) + monitor.reportVmStateChange(clock.millis(), it.server) } } .collect() diff --git a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/experiment/Portfolio.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/Portfolio.kt index 6a40f5fb..37cf2880 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/experiment/Portfolio.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/Portfolio.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,20 +20,20 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.experiment +package org.opendc.experiments.sc20.experiment -import com.atlarge.opendc.experiments.sc20.experiment.model.OperationalPhenomena -import com.atlarge.opendc.experiments.sc20.experiment.model.Topology -import com.atlarge.opendc.experiments.sc20.experiment.model.Workload -import com.atlarge.opendc.experiments.sc20.runner.ContainerExperimentDescriptor +import org.opendc.experiments.sc20.experiment.model.OperationalPhenomena +import org.opendc.experiments.sc20.experiment.model.Topology +import org.opendc.experiments.sc20.experiment.model.Workload +import org.opendc.experiments.sc20.runner.ContainerExperimentDescriptor /** * A portfolio represents a collection of scenarios are tested. */ public abstract class Portfolio( override val parent: Experiment, - val id: Int, - val name: String + public val id: Int, + public val name: String ) : ContainerExperimentDescriptor() { /** * The topologies to consider. @@ -60,7 +58,7 @@ public abstract class Portfolio( /** * The number of repetitions to perform. */ - open val repetitions: Int = 32 + public open val repetitions: Int = 32 /** * Resolve the children of this container. diff --git a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/experiment/Portfolios.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/Portfolios.kt index 09a6ce40..249a63b9 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/experiment/Portfolios.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/Portfolios.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,12 +20,12 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.experiment +package org.opendc.experiments.sc20.experiment -import com.atlarge.opendc.experiments.sc20.experiment.model.* +import org.opendc.experiments.sc20.experiment.model.* public class HorVerPortfolio(parent: Experiment, id: Int) : Portfolio(parent, id, "horizontal_vs_vertical") { - override val topologies = listOf( + override val topologies: List<Topology> = listOf( Topology("base"), Topology("rep-vol-hor-hom"), Topology("rep-vol-hor-het"), @@ -39,24 +37,24 @@ public class HorVerPortfolio(parent: Experiment, id: Int) : Portfolio(parent, id Topology("exp-vol-ver-het") ) - override val workloads = listOf( + override val workloads: List<Workload> = listOf( Workload("solvinity", 0.1), Workload("solvinity", 0.25), Workload("solvinity", 0.5), Workload("solvinity", 1.0) ) - override val operationalPhenomenas = listOf( + override val operationalPhenomenas: List<OperationalPhenomena> = listOf( OperationalPhenomena(failureFrequency = 24.0 * 7, hasInterference = true) ) - override val allocationPolicies = listOf( + override val allocationPolicies: List<String> = listOf( "active-servers" ) } public class MoreVelocityPortfolio(parent: Experiment, id: Int) : Portfolio(parent, id, "more_velocity") { - override val topologies = listOf( + override val topologies: List<Topology> = listOf( Topology("base"), Topology("rep-vel-ver-hom"), Topology("rep-vel-ver-het"), @@ -64,18 +62,18 @@ public class MoreVelocityPortfolio(parent: Experiment, id: Int) : Portfolio(pare Topology("exp-vel-ver-het") ) - override val workloads = listOf( + override val workloads: List<Workload> = listOf( Workload("solvinity", 0.1), Workload("solvinity", 0.25), Workload("solvinity", 0.5), Workload("solvinity", 1.0) ) - override val operationalPhenomenas = listOf( + override val operationalPhenomenas: List<OperationalPhenomena> = listOf( OperationalPhenomena(failureFrequency = 24.0 * 7, hasInterference = true) ) - override val allocationPolicies = listOf( + override val allocationPolicies: List<String> = listOf( "active-servers" ) } @@ -83,14 +81,14 @@ public class MoreVelocityPortfolio(parent: Experiment, id: Int) : Portfolio(pare public class CompositeWorkloadPortfolio(parent: Experiment, id: Int) : Portfolio(parent, id, "composite-workload") { private val totalSampleLoad = 1.3301733005049648E12 - override val topologies = listOf( + override val topologies: List<Topology> = listOf( Topology("base"), Topology("exp-vol-hor-hom"), Topology("exp-vol-ver-hom"), Topology("exp-vel-ver-hom") ) - override val workloads = listOf( + override val workloads: List<Workload> = listOf( CompositeWorkload( "all-azure", listOf(Workload("solvinity-short", 0.0), Workload("azure", 1.0)), @@ -118,35 +116,36 @@ public class CompositeWorkloadPortfolio(parent: Experiment, id: Int) : Portfolio ) ) - override val operationalPhenomenas = listOf( + override val operationalPhenomenas: List<OperationalPhenomena> = listOf( OperationalPhenomena(failureFrequency = 24.0 * 7, hasInterference = false) ) - override val allocationPolicies = listOf( + override val allocationPolicies: List<String> = listOf( "active-servers" ) } -public class OperationalPhenomenaPortfolio(parent: Experiment, id: Int) : Portfolio(parent, id, "operational_phenomena") { - override val topologies = listOf( +public class OperationalPhenomenaPortfolio(parent: Experiment, id: Int) : + Portfolio(parent, id, "operational_phenomena") { + override val topologies: List<Topology> = listOf( Topology("base") ) - override val workloads = listOf( + override val workloads: List<Workload> = listOf( Workload("solvinity", 0.1), Workload("solvinity", 0.25), Workload("solvinity", 0.5), Workload("solvinity", 1.0) ) - override val operationalPhenomenas = listOf( + override val operationalPhenomenas: List<OperationalPhenomena> = listOf( OperationalPhenomena(failureFrequency = 24.0 * 7, hasInterference = true), OperationalPhenomena(failureFrequency = 0.0, hasInterference = true), OperationalPhenomena(failureFrequency = 24.0 * 7, hasInterference = false), OperationalPhenomena(failureFrequency = 0.0, hasInterference = false) ) - override val allocationPolicies = listOf( + override val allocationPolicies: List<String> = listOf( "mem", "mem-inv", "core-mem", @@ -158,19 +157,19 @@ public class OperationalPhenomenaPortfolio(parent: Experiment, id: Int) : Portfo } public class ReplayPortfolio(parent: Experiment, id: Int) : Portfolio(parent, id, "replay") { - override val topologies = listOf( + override val topologies: List<Topology> = listOf( Topology("base") ) - override val workloads = listOf( + override val workloads: List<Workload> = listOf( Workload("solvinity", 1.0) ) - override val operationalPhenomenas = listOf( + override val operationalPhenomenas: List<OperationalPhenomena> = listOf( OperationalPhenomena(failureFrequency = 0.0, hasInterference = false) ) - override val allocationPolicies = listOf( + override val allocationPolicies: List<String> = listOf( "replay", "active-servers" ) @@ -195,14 +194,14 @@ public class TestPortfolio(parent: Experiment, id: Int) : Portfolio(parent, id, } public class MoreHpcPortfolio(parent: Experiment, id: Int) : Portfolio(parent, id, "more_hpc") { - override val topologies = listOf( + override val topologies: List<Topology> = listOf( Topology("base"), Topology("exp-vol-hor-hom"), Topology("exp-vol-ver-hom"), Topology("exp-vel-ver-hom") ) - override val workloads = listOf( + override val workloads: List<Workload> = listOf( Workload("solvinity", 0.0, samplingStrategy = SamplingStrategy.HPC), Workload("solvinity", 0.25, samplingStrategy = SamplingStrategy.HPC), Workload("solvinity", 0.5, samplingStrategy = SamplingStrategy.HPC), @@ -212,11 +211,11 @@ public class MoreHpcPortfolio(parent: Experiment, id: Int) : Portfolio(parent, i Workload("solvinity", 1.0, samplingStrategy = SamplingStrategy.HPC_LOAD) ) - override val operationalPhenomenas = listOf( + override val operationalPhenomenas: List<OperationalPhenomena> = listOf( OperationalPhenomena(failureFrequency = 24.0 * 7, hasInterference = true) ) - override val allocationPolicies = listOf( + override val allocationPolicies: List<String> = listOf( "active-servers" ) } diff --git a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/experiment/Run.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/Run.kt index 1580e4dd..660fc882 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/experiment/Run.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/Run.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,29 +20,25 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.experiment +package org.opendc.experiments.sc20.experiment -import com.atlarge.odcsim.SimulationEngineProvider -import com.atlarge.opendc.compute.virt.service.allocation.AvailableCoreMemoryAllocationPolicy -import com.atlarge.opendc.compute.virt.service.allocation.AvailableMemoryAllocationPolicy -import com.atlarge.opendc.compute.virt.service.allocation.NumberOfActiveServersAllocationPolicy -import com.atlarge.opendc.compute.virt.service.allocation.ProvisionedCoresAllocationPolicy -import com.atlarge.opendc.compute.virt.service.allocation.RandomAllocationPolicy -import com.atlarge.opendc.compute.virt.service.allocation.ReplayAllocationPolicy -import com.atlarge.opendc.experiments.sc20.experiment.model.CompositeWorkload -import com.atlarge.opendc.experiments.sc20.experiment.monitor.ParquetExperimentMonitor -import com.atlarge.opendc.experiments.sc20.runner.TrialExperimentDescriptor -import com.atlarge.opendc.experiments.sc20.runner.execution.ExperimentExecutionContext -import com.atlarge.opendc.experiments.sc20.trace.Sc20ParquetTraceReader -import com.atlarge.opendc.experiments.sc20.trace.Sc20RawParquetTraceReader -import com.atlarge.opendc.format.environment.sc20.Sc20ClusterEnvironmentReader -import java.io.File -import java.util.ServiceLoader -import kotlin.random.Random +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.cancel import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.launch +import kotlinx.coroutines.test.TestCoroutineScope import mu.KotlinLogging +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 +import org.opendc.experiments.sc20.runner.execution.ExperimentExecutionContext +import org.opendc.experiments.sc20.trace.Sc20ParquetTraceReader +import org.opendc.experiments.sc20.trace.Sc20RawParquetTraceReader +import org.opendc.format.environment.sc20.Sc20ClusterEnvironmentReader +import org.opendc.simulator.utils.DelayControllerClockAdapter +import java.io.File +import kotlin.random.Random /** * The logger for the experiment scenario. @@ -52,19 +46,15 @@ import mu.KotlinLogging private val logger = KotlinLogging.logger {} /** - * The provider for the simulation engine to use. - */ -private val provider = ServiceLoader.load(SimulationEngineProvider::class.java).first() - -/** * An experiment run represent a single invocation of a trial and is used to distinguish between repetitions of the * same set of parameters. */ +@OptIn(ExperimentalCoroutinesApi::class) public data class Run(override val parent: Scenario, val id: Int, val seed: Int) : TrialExperimentDescriptor() { override suspend fun invoke(context: ExperimentExecutionContext) { val experiment = parent.parent.parent - val system = provider("experiment-$id") - val root = system.newDomain("root") + val testScope = TestCoroutineScope() + val clock = DelayControllerClockAdapter(testScope) val seeder = Random(seed) val environment = Sc20ClusterEnvironmentReader(File(experiment.environments, "${parent.topology.name}.txt")) @@ -112,9 +102,10 @@ public data class Run(override val parent: Scenario, val id: Int, val seed: Int) parent.parent.parent.bufferSize ) - root.launch { + testScope.launch { val (bareMetalProvisioner, scheduler) = createProvisioner( - root, + this, + clock, environment, allocationPolicy ) @@ -122,6 +113,8 @@ public data class Run(override val parent: Scenario, val id: Int, val seed: Int) val failureDomain = if (parent.operationalPhenomena.failureFrequency > 0) { logger.debug("ENABLING failures") createFailureDomain( + this, + clock, seeder.nextInt(), parent.operationalPhenomena.failureFrequency, bareMetalProvisioner, @@ -131,13 +124,14 @@ public data class Run(override val parent: Scenario, val id: Int, val seed: Int) null } - attachMonitor(scheduler, monitor) + attachMonitor(this, clock, scheduler, monitor) processTrace( + this, + clock, trace, scheduler, chan, - monitor, - experiment.vmPlacements + monitor ) logger.debug("SUBMIT=${scheduler.submittedVms}") @@ -151,9 +145,8 @@ public data class Run(override val parent: Scenario, val id: Int, val seed: Int) } try { - system.run() + testScope.advanceUntilIdle() } finally { - system.terminate() monitor.close() } } diff --git a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/experiment/Scenario.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/Scenario.kt index 98bc7fc2..d092ddd5 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/experiment/Scenario.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/Scenario.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,25 +20,25 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.experiment +package org.opendc.experiments.sc20.experiment -import com.atlarge.opendc.experiments.sc20.experiment.model.OperationalPhenomena -import com.atlarge.opendc.experiments.sc20.experiment.model.Topology -import com.atlarge.opendc.experiments.sc20.experiment.model.Workload -import com.atlarge.opendc.experiments.sc20.runner.ContainerExperimentDescriptor -import com.atlarge.opendc.experiments.sc20.runner.ExperimentDescriptor +import org.opendc.experiments.sc20.experiment.model.OperationalPhenomena +import org.opendc.experiments.sc20.experiment.model.Topology +import org.opendc.experiments.sc20.experiment.model.Workload +import org.opendc.experiments.sc20.runner.ContainerExperimentDescriptor +import org.opendc.experiments.sc20.runner.ExperimentDescriptor /** * A scenario represents a single point in the design space (a unique combination of parameters). */ public class Scenario( override val parent: Portfolio, - val id: Int, - val repetitions: Int, - val topology: Topology, - val workload: Workload, - val allocationPolicy: String, - val operationalPhenomena: OperationalPhenomena + public val id: Int, + public val repetitions: Int, + public val topology: Topology, + public val workload: Workload, + public val allocationPolicy: String, + public val operationalPhenomena: OperationalPhenomena ) : ContainerExperimentDescriptor() { override val children: Sequence<ExperimentDescriptor> = sequence { repeat(repetitions) { i -> yield(Run(this@Scenario, i, i)) } diff --git a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/experiment/model/OperationalPhenomena.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/model/OperationalPhenomena.kt index af99df84..b22f4c9e 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/experiment/model/OperationalPhenomena.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/model/OperationalPhenomena.kt @@ -22,7 +22,7 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.experiment.model +package org.opendc.experiments.sc20.experiment.model /** * Operation phenomena during experiments. diff --git a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/experiment/model/Topology.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/model/Topology.kt index ea09688b..95062fda 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/experiment/model/Topology.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/model/Topology.kt @@ -22,7 +22,7 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.experiment.model +package org.opendc.experiments.sc20.experiment.model /** * The topology topology on which we test the workload. diff --git a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/experiment/model/Workload.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/model/Workload.kt index d75ca6f9..ba95f544 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/experiment/model/Workload.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/experiment/model/Workload.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,9 +20,9 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.experiment.model +package org.opendc.experiments.sc20.experiment.model -enum class SamplingStrategy { +public enum class SamplingStrategy { REGULAR, HPC, HPC_LOAD @@ -33,10 +31,14 @@ enum class SamplingStrategy { /** * A workload that is considered for a scenario. */ -public open class Workload(open val name: String, val fraction: Double, val samplingStrategy: SamplingStrategy = SamplingStrategy.REGULAR) +public open class Workload( + public open val name: String, + public val fraction: Double, + public val samplingStrategy: SamplingStrategy = SamplingStrategy.REGULAR +) /** * A workload that is composed of multiple workloads. */ -public class CompositeWorkload(override val name: String, val workloads: List<Workload>, val totalLoad: Double) : +public class CompositeWorkload(override val name: String, public val workloads: List<Workload>, public val totalLoad: Double) : Workload(name, -1.0) diff --git a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/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 1f674f00..18ba2c33 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/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 @@ -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,40 +20,41 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.experiment.monitor +package org.opendc.experiments.sc20.experiment.monitor -import com.atlarge.opendc.compute.core.Server -import com.atlarge.opendc.compute.virt.driver.VirtDriver -import com.atlarge.opendc.compute.virt.service.VirtProvisioningEvent +import org.opendc.compute.core.Server +import org.opendc.compute.core.virt.driver.VirtDriver +import org.opendc.compute.core.virt.service.VirtProvisioningEvent import java.io.Closeable /** * A monitor watches the events of an experiment. */ -interface ExperimentMonitor : Closeable { +public interface ExperimentMonitor : Closeable { /** * This method is invoked when the state of a VM changes. */ - fun reportVmStateChange(time: Long, server: Server) {} + public fun reportVmStateChange(time: Long, server: Server) {} /** * This method is invoked when the state of a host changes. */ - fun reportHostStateChange( + public fun reportHostStateChange( time: Long, driver: VirtDriver, server: Server - ) {} + ) { + } /** * Report the power consumption of a host. */ - fun reportPowerConsumption(host: Server, draw: Double) {} + public fun reportPowerConsumption(host: Server, draw: Double) {} /** * This method is invoked for a host for each slice that is finishes. */ - fun reportHostSlice( + public fun reportHostSlice( time: Long, requestedBurst: Long, grantedBurst: Long, @@ -66,10 +65,11 @@ interface ExperimentMonitor : Closeable { numberOfDeployedImages: Int, hostServer: Server, duration: Long = 5 * 60 * 1000L - ) {} + ) { + } /** * This method is invoked for a provisioner event. */ - fun reportProvisionerMetrics(time: Long, event: VirtProvisioningEvent.MetricsAvailable) {} + public fun reportProvisionerMetrics(time: Long, event: VirtProvisioningEvent.MetricsAvailable) {} } diff --git a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/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 b931fef9..3eb9362c 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/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 @@ -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,17 +20,17 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.experiment.monitor +package org.opendc.experiments.sc20.experiment.monitor -import com.atlarge.opendc.compute.core.Server -import com.atlarge.opendc.compute.virt.driver.VirtDriver -import com.atlarge.opendc.compute.virt.service.VirtProvisioningEvent -import com.atlarge.opendc.experiments.sc20.telemetry.HostEvent -import com.atlarge.opendc.experiments.sc20.telemetry.ProvisionerEvent -import com.atlarge.opendc.experiments.sc20.telemetry.parquet.ParquetHostEventWriter -import com.atlarge.opendc.experiments.sc20.telemetry.parquet.ParquetProvisionerEventWriter -import java.io.File import mu.KotlinLogging +import org.opendc.compute.core.Server +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 +import org.opendc.experiments.sc20.telemetry.parquet.ParquetProvisionerEventWriter +import java.io.File /** * The logger instance to use. @@ -42,7 +40,7 @@ private val logger = KotlinLogging.logger {} /** * An [ExperimentMonitor] that logs the events to a Parquet file. */ -class ParquetExperimentMonitor(base: File, partition: String, bufferSize: Int) : ExperimentMonitor { +public class ParquetExperimentMonitor(base: File, partition: String, bufferSize: Int) : ExperimentMonitor { private val hostWriter = ParquetHostEventWriter( File(base, "host-metrics/$partition/data.parquet"), bufferSize @@ -59,7 +57,7 @@ class ParquetExperimentMonitor(base: File, partition: String, bufferSize: Int) : 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/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/reporter/ConsoleExperimentReporter.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/reporter/ConsoleExperimentReporter.kt index b446abc8..af61622a 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/reporter/ConsoleExperimentReporter.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/reporter/ConsoleExperimentReporter.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,20 +20,20 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.reporter +package org.opendc.experiments.sc20.reporter -import com.atlarge.opendc.experiments.sc20.experiment.Run -import com.atlarge.opendc.experiments.sc20.runner.ExperimentDescriptor -import com.atlarge.opendc.experiments.sc20.runner.execution.ExperimentExecutionListener -import com.atlarge.opendc.experiments.sc20.runner.execution.ExperimentExecutionResult import me.tongfei.progressbar.ProgressBar import me.tongfei.progressbar.ProgressBarBuilder import mu.KotlinLogging +import org.opendc.experiments.sc20.experiment.Run +import org.opendc.experiments.sc20.runner.ExperimentDescriptor +import org.opendc.experiments.sc20.runner.execution.ExperimentExecutionListener +import org.opendc.experiments.sc20.runner.execution.ExperimentExecutionResult /** * A reporter that reports the experiment progress to the console. */ -public class ConsoleExperimentReporter : ExperimentExecutionListener { +public class ConsoleExperimentReporter : ExperimentExecutionListener, AutoCloseable { /** * The active [Run]s. */ @@ -82,4 +80,8 @@ public class ConsoleExperimentReporter : ExperimentExecutionListener { } override fun executionStarted(descriptor: ExperimentDescriptor) {} + + override fun close() { + pb.close() + } } diff --git a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/runner/ContainerExperimentDescriptor.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/runner/ContainerExperimentDescriptor.kt index dac32586..d70e8c9a 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/runner/ContainerExperimentDescriptor.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/runner/ContainerExperimentDescriptor.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,12 +20,12 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.runner +package org.opendc.experiments.sc20.runner -import com.atlarge.opendc.experiments.sc20.runner.execution.ExperimentExecutionContext -import com.atlarge.opendc.experiments.sc20.runner.execution.ExperimentExecutionResult import kotlinx.coroutines.launch import kotlinx.coroutines.supervisorScope +import org.opendc.experiments.sc20.runner.execution.ExperimentExecutionContext +import org.opendc.experiments.sc20.runner.execution.ExperimentExecutionResult /** * An abstract [ExperimentDescriptor] specifically for containers. diff --git a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/runner/ExperimentDescriptor.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/runner/ExperimentDescriptor.kt index 64b6b767..1e67c086 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/runner/ExperimentDescriptor.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/runner/ExperimentDescriptor.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,9 +20,9 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.runner +package org.opendc.experiments.sc20.runner -import com.atlarge.opendc.experiments.sc20.runner.execution.ExperimentExecutionContext +import org.opendc.experiments.sc20.runner.execution.ExperimentExecutionContext import java.io.Serializable /** @@ -43,7 +41,7 @@ public abstract class ExperimentDescriptor : Serializable { /** * The type of descriptor. */ - abstract val type: Type + public abstract val type: Type /** * A flag to indicate that this descriptor is a root descriptor. @@ -54,7 +52,7 @@ public abstract class ExperimentDescriptor : Serializable { /** * A flag to indicate that this descriptor describes an experiment trial. */ - val isTrial: Boolean + public val isTrial: Boolean get() = type == Type.TRIAL /** @@ -67,7 +65,7 @@ public abstract class ExperimentDescriptor : Serializable { /** * The types of experiment descriptors. */ - enum class Type { + public enum class Type { /** * A composition of multiple experiment descriptions whose invocation happens on a single thread. */ diff --git a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/runner/ExperimentRunner.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/runner/ExperimentRunner.kt index 77f970fe..a59481c0 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/runner/ExperimentRunner.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/runner/ExperimentRunner.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,9 +20,9 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.runner +package org.opendc.experiments.sc20.runner -import com.atlarge.opendc.experiments.sc20.runner.execution.ExperimentExecutionListener +import org.opendc.experiments.sc20.runner.execution.ExperimentExecutionListener /** * An [ExperimentRunner] facilitates discovery and execution of experiments. @@ -33,12 +31,12 @@ public interface ExperimentRunner { /** * The unique identifier of this runner. */ - val id: String + public val id: String /** * The version of this runner. */ - val version: String? + public val version: String? get() = null /** diff --git a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/runner/TrialExperimentDescriptor.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/runner/TrialExperimentDescriptor.kt index cf05416a..abc52997 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/runner/TrialExperimentDescriptor.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/runner/TrialExperimentDescriptor.kt @@ -22,7 +22,7 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.runner +package org.opendc.experiments.sc20.runner /** * An abstract [ExperimentDescriptor] specifically for trials. diff --git a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/runner/execution/ExperimentExecutionContext.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/runner/execution/ExperimentExecutionContext.kt index 9a04c491..942eb891 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/runner/execution/ExperimentExecutionContext.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/runner/execution/ExperimentExecutionContext.kt @@ -22,7 +22,7 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.runner.execution +package org.opendc.experiments.sc20.runner.execution /** * The execution context of an experiment. diff --git a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/runner/execution/ExperimentExecutionListener.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/runner/execution/ExperimentExecutionListener.kt index f6df0524..42fef164 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/runner/execution/ExperimentExecutionListener.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/runner/execution/ExperimentExecutionListener.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,27 +20,27 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.runner.execution +package org.opendc.experiments.sc20.runner.execution -import com.atlarge.opendc.experiments.sc20.runner.ExperimentDescriptor +import org.opendc.experiments.sc20.runner.ExperimentDescriptor /** * Listener to be notified of experiment execution events by experiment runners. */ -interface ExperimentExecutionListener { +public interface ExperimentExecutionListener { /** * A method that is invoked when a new [ExperimentDescriptor] is registered. */ - fun descriptorRegistered(descriptor: ExperimentDescriptor) + public fun descriptorRegistered(descriptor: ExperimentDescriptor) /** * A method that is invoked when when the execution of a leaf or subtree of the experiment tree has finished, * regardless of the outcome. */ - fun executionFinished(descriptor: ExperimentDescriptor, result: ExperimentExecutionResult) + public fun executionFinished(descriptor: ExperimentDescriptor, result: ExperimentExecutionResult) /** * A method that is invoked when the execution of a leaf or subtree of the experiment tree is about to be started. */ - fun executionStarted(descriptor: ExperimentDescriptor) + public fun executionStarted(descriptor: ExperimentDescriptor) } diff --git a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/runner/execution/ExperimentExecutionResult.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/runner/execution/ExperimentExecutionResult.kt index 057e1f92..a765c264 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/runner/execution/ExperimentExecutionResult.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/runner/execution/ExperimentExecutionResult.kt @@ -22,7 +22,7 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.runner.execution +package org.opendc.experiments.sc20.runner.execution import java.io.Serializable diff --git a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/runner/execution/ExperimentScheduler.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/runner/execution/ExperimentScheduler.kt index 96678abf..70095ccd 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/runner/execution/ExperimentScheduler.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/runner/execution/ExperimentScheduler.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,27 +20,27 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.runner.execution +package org.opendc.experiments.sc20.runner.execution -import com.atlarge.opendc.experiments.sc20.runner.ExperimentDescriptor +import org.opendc.experiments.sc20.runner.ExperimentDescriptor import java.io.Closeable /** * A interface for scheduling the execution of experiment trials over compute resources (threads/containers/vms) */ -interface ExperimentScheduler : Closeable { +public interface ExperimentScheduler : Closeable { /** * Allocate a [Worker] for executing an experiment trial. This method may suspend in case no resources are directly * available at the moment. * * @return The available worker. */ - suspend fun allocate(): ExperimentScheduler.Worker + public suspend fun allocate(): ExperimentScheduler.Worker /** * An isolated worker of an [ExperimentScheduler] that is responsible for executing a single experiment trial. */ - interface Worker { + public interface Worker { /** * Dispatch the specified [ExperimentDescriptor] to execute some time in the future and return the results of * the trial. @@ -50,7 +48,7 @@ interface ExperimentScheduler : Closeable { * @param descriptor The descriptor to execute. * @param context The context to execute the descriptor in. */ - suspend operator fun invoke( + public suspend operator fun invoke( descriptor: ExperimentDescriptor, context: ExperimentExecutionContext ) diff --git a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/runner/execution/ThreadPoolExperimentScheduler.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/runner/execution/ThreadPoolExperimentScheduler.kt index a8ee59a8..942faed1 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/runner/execution/ThreadPoolExperimentScheduler.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/runner/execution/ThreadPoolExperimentScheduler.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,22 +20,22 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.runner.execution +package org.opendc.experiments.sc20.runner.execution -import com.atlarge.opendc.experiments.sc20.runner.ExperimentDescriptor -import java.util.concurrent.Executors import kotlinx.coroutines.asCoroutineDispatcher import kotlinx.coroutines.launch import kotlinx.coroutines.supervisorScope import kotlinx.coroutines.sync.Semaphore import kotlinx.coroutines.withContext +import org.opendc.experiments.sc20.runner.ExperimentDescriptor +import java.util.concurrent.Executors /** * An [ExperimentScheduler] that runs experiments using a local thread pool. * * @param parallelism The maximum amount of parallel workers (default is the number of available processors). */ -class ThreadPoolExperimentScheduler(parallelism: Int = Runtime.getRuntime().availableProcessors() + 1) : ExperimentScheduler { +public class ThreadPoolExperimentScheduler(parallelism: Int = Runtime.getRuntime().availableProcessors() + 1) : ExperimentScheduler { private val dispatcher = Executors.newCachedThreadPool().asCoroutineDispatcher() private val tickets = Semaphore(parallelism) @@ -54,7 +52,10 @@ class ThreadPoolExperimentScheduler(parallelism: Int = Runtime.getRuntime().avai launch { context.listener.descriptorRegistered(descriptor) } } - override fun executionFinished(descriptor: ExperimentDescriptor, result: ExperimentExecutionResult) { + override fun executionFinished( + descriptor: ExperimentDescriptor, + result: ExperimentExecutionResult + ) { launch { context.listener.executionFinished(descriptor, result) } } @@ -78,5 +79,5 @@ class ThreadPoolExperimentScheduler(parallelism: Int = Runtime.getRuntime().avai } } - override fun close() = dispatcher.close() + override fun close(): Unit = dispatcher.close() } diff --git a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/runner/internal/DefaultExperimentRunner.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/runner/internal/DefaultExperimentRunner.kt index 28a19172..26e4df89 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/runner/internal/DefaultExperimentRunner.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/runner/internal/DefaultExperimentRunner.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,28 +20,28 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.runner.internal +package org.opendc.experiments.sc20.runner.internal -import com.atlarge.opendc.experiments.sc20.runner.ExperimentDescriptor -import com.atlarge.opendc.experiments.sc20.runner.ExperimentRunner -import com.atlarge.opendc.experiments.sc20.runner.execution.ExperimentExecutionContext -import com.atlarge.opendc.experiments.sc20.runner.execution.ExperimentExecutionListener -import com.atlarge.opendc.experiments.sc20.runner.execution.ExperimentExecutionResult -import com.atlarge.opendc.experiments.sc20.runner.execution.ExperimentScheduler -import java.util.concurrent.ConcurrentHashMap import kotlinx.coroutines.runBlocking +import org.opendc.experiments.sc20.runner.ExperimentDescriptor +import org.opendc.experiments.sc20.runner.ExperimentRunner +import org.opendc.experiments.sc20.runner.execution.ExperimentExecutionContext +import org.opendc.experiments.sc20.runner.execution.ExperimentExecutionListener +import org.opendc.experiments.sc20.runner.execution.ExperimentExecutionResult +import org.opendc.experiments.sc20.runner.execution.ExperimentScheduler +import java.util.concurrent.ConcurrentHashMap /** * The default implementation of the [ExperimentRunner] interface. * * @param scheduler The scheduler to use. */ -public class DefaultExperimentRunner(val scheduler: ExperimentScheduler) : ExperimentRunner { +public class DefaultExperimentRunner(private val scheduler: ExperimentScheduler) : ExperimentRunner { override val id: String = "default" override val version: String? = "1.0" - override fun execute(root: ExperimentDescriptor, listener: ExperimentExecutionListener) = runBlocking { + override fun execute(root: ExperimentDescriptor, listener: ExperimentExecutionListener): Unit = runBlocking { val context = object : ExperimentExecutionContext { override val listener: ExperimentExecutionListener = listener override val scheduler: ExperimentScheduler = this@DefaultExperimentRunner.scheduler diff --git a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/telemetry/Event.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/telemetry/Event.kt index c1e14e2a..38a4a227 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/telemetry/Event.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/telemetry/Event.kt @@ -22,12 +22,12 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.telemetry +package org.opendc.experiments.sc20.telemetry /** * An event that occurs within the system. */ -public abstract class Event(val name: String) { +public abstract class Event(public val name: String) { /** * The time of occurrence of this event. */ diff --git a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/telemetry/HostEvent.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/telemetry/HostEvent.kt index b9030172..042d204e 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/telemetry/HostEvent.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/telemetry/HostEvent.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,24 +20,24 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.telemetry +package org.opendc.experiments.sc20.telemetry -import com.atlarge.opendc.compute.core.Server +import org.opendc.compute.core.Server /** * A periodic report of the host machine metrics. */ -data class HostEvent( +public data class HostEvent( override val timestamp: Long, - val duration: Long, - val host: Server, - val vmCount: Int, - val requestedBurst: Long, - val grantedBurst: Long, - val overcommissionedBurst: Long, - val interferedBurst: Long, - val cpuUsage: Double, - val cpuDemand: Double, - val powerDraw: Double, - val cores: Int + public val duration: Long, + public val host: Server, + public val vmCount: Int, + public val requestedBurst: Long, + public val grantedBurst: Long, + public val overcommissionedBurst: Long, + public val interferedBurst: Long, + public val cpuUsage: Double, + public val cpuDemand: Double, + public val powerDraw: Double, + public val cores: Int ) : Event("host-metrics") diff --git a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/telemetry/ProvisionerEvent.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/telemetry/ProvisionerEvent.kt index df619632..d063bc54 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/telemetry/ProvisionerEvent.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/telemetry/ProvisionerEvent.kt @@ -22,18 +22,18 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.telemetry +package org.opendc.experiments.sc20.telemetry /** * A periodic report of the provisioner's metrics. */ -data class ProvisionerEvent( +public data class ProvisionerEvent( override val timestamp: Long, - val totalHostCount: Int, - val availableHostCount: Int, - val totalVmCount: Int, - val activeVmCount: Int, - val inactiveVmCount: Int, - val waitingVmCount: Int, - val failedVmCount: Int + public val totalHostCount: Int, + public val availableHostCount: Int, + public val totalVmCount: Int, + public val activeVmCount: Int, + public val inactiveVmCount: Int, + public val waitingVmCount: Int, + public val failedVmCount: Int ) : Event("provisioner-metrics") diff --git a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/telemetry/RunEvent.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/telemetry/RunEvent.kt index 497d2c3f..3bcd10a1 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/telemetry/RunEvent.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/telemetry/RunEvent.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,14 +20,14 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.telemetry +package org.opendc.experiments.sc20.telemetry -import com.atlarge.opendc.experiments.sc20.experiment.Run +import org.opendc.experiments.sc20.experiment.Run /** * A periodic report of the host machine metrics. */ -data class RunEvent( - val run: Run, +public data class RunEvent( + public val run: Run, override val timestamp: Long ) : Event("run") diff --git a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/telemetry/VmEvent.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/telemetry/VmEvent.kt index 7289fb21..c18069c9 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/telemetry/VmEvent.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/telemetry/VmEvent.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,22 +20,22 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.telemetry +package org.opendc.experiments.sc20.telemetry -import com.atlarge.opendc.compute.core.Server +import org.opendc.compute.core.Server /** * A periodic report of a virtual machine's metrics. */ -data class VmEvent( +public data class VmEvent( override val timestamp: Long, - val duration: Long, - val vm: Server, - val host: Server, - val requestedBurst: Long, - val grantedBurst: Long, - val overcommissionedBurst: Long, - val interferedBurst: Long, - val cpuUsage: Double, - val cpuDemand: Double + public val duration: Long, + public val vm: Server, + public val host: Server, + public val requestedBurst: Long, + public val grantedBurst: Long, + public val overcommissionedBurst: Long, + public val interferedBurst: Long, + public val cpuUsage: Double, + public val cpuDemand: Double ) : Event("vm-metrics") diff --git a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/telemetry/parquet/ParquetEventWriter.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/telemetry/parquet/ParquetEventWriter.kt index e42ac654..79bc23db 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/telemetry/parquet/ParquetEventWriter.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/telemetry/parquet/ParquetEventWriter.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,20 +20,20 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.telemetry.parquet +package org.opendc.experiments.sc20.telemetry.parquet -import com.atlarge.opendc.experiments.sc20.telemetry.Event -import java.io.Closeable -import java.io.File -import java.util.concurrent.ArrayBlockingQueue -import java.util.concurrent.BlockingQueue -import kotlin.concurrent.thread import mu.KotlinLogging import org.apache.avro.Schema import org.apache.avro.generic.GenericData import org.apache.hadoop.fs.Path import org.apache.parquet.avro.AvroParquetWriter import org.apache.parquet.hadoop.metadata.CompressionCodecName +import org.opendc.experiments.sc20.telemetry.Event +import java.io.Closeable +import java.io.File +import java.util.concurrent.ArrayBlockingQueue +import java.util.concurrent.BlockingQueue +import kotlin.concurrent.thread /** * The logging instance to use. @@ -52,6 +50,16 @@ public open class ParquetEventWriter<in T : Event>( private val bufferSize: Int = 4096 ) : Runnable, Closeable { /** + * The writer to write the Parquet file. + */ + private val writer = AvroParquetWriter.builder<GenericData.Record>(Path(path.absolutePath)) + .withSchema(schema) + .withCompressionCodec(CompressionCodecName.SNAPPY) + .withPageSize(4 * 1024 * 1024) // For compression + .withRowGroupSize(16 * 1024 * 1024) // For write buffering (Page size) + .build() + + /** * The queue of commands to process. */ private val queue: BlockingQueue<Action> = ArrayBlockingQueue(bufferSize) @@ -59,7 +67,7 @@ public open class ParquetEventWriter<in T : Event>( /** * The thread that is responsible for writing the Parquet records. */ - private val writerThread = thread(start = true, name = "parquet-writer") { run() } + private val writerThread = thread(start = false, name = "parquet-writer") { run() } /** * Write the specified metrics to the database. @@ -76,17 +84,14 @@ public open class ParquetEventWriter<in T : Event>( writerThread.join() } + init { + writerThread.start() + } + /** * Start the writer thread. */ override fun run() { - val writer = AvroParquetWriter.builder<GenericData.Record>(Path(path.absolutePath)) - .withSchema(schema) - .withCompressionCodec(CompressionCodecName.SNAPPY) - .withPageSize(4 * 1024 * 1024) // For compression - .withRowGroupSize(16 * 1024 * 1024) // For write buffering (Page size) - .build() - try { loop@ while (true) { val action = queue.take() @@ -107,15 +112,15 @@ public open class ParquetEventWriter<in T : Event>( } } - sealed class Action { + public sealed class Action { /** * A poison pill that will stop the writer thread. */ - object Stop : Action() + public object Stop : Action() /** * Write the specified metrics to the database. */ - data class Write<out T : Event>(val event: T) : Action() + public data class Write<out T : Event>(val event: T) : Action() } } diff --git a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/telemetry/parquet/ParquetHostEventWriter.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/telemetry/parquet/ParquetHostEventWriter.kt index 9fa4e0fb..bd4eae37 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/telemetry/parquet/ParquetHostEventWriter.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/telemetry/parquet/ParquetHostEventWriter.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,13 +20,13 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.telemetry.parquet +package org.opendc.experiments.sc20.telemetry.parquet -import com.atlarge.opendc.experiments.sc20.telemetry.HostEvent -import java.io.File import org.apache.avro.Schema import org.apache.avro.SchemaBuilder import org.apache.avro.generic.GenericData +import org.opendc.experiments.sc20.telemetry.HostEvent +import java.io.File /** * A Parquet event writer for [HostEvent]s. @@ -38,8 +36,8 @@ public class ParquetHostEventWriter(path: File, bufferSize: Int) : override fun toString(): String = "host-writer" - companion object { - val convert: (HostEvent, GenericData.Record) -> Unit = { event, record -> + public companion object { + private val convert: (HostEvent, GenericData.Record) -> Unit = { event, record -> // record.put("portfolio_id", event.run.parent.parent.id) // record.put("scenario_id", event.run.parent.id) // record.put("run_id", event.run.id) @@ -58,9 +56,9 @@ public class ParquetHostEventWriter(path: File, bufferSize: Int) : record.put("cores", event.cores) } - val schema: Schema = SchemaBuilder + private val schema: Schema = SchemaBuilder .record("host_metrics") - .namespace("com.atlarge.opendc.experiments.sc20") + .namespace("org.opendc.experiments.sc20") .fields() // .name("portfolio_id").type().intType().noDefault() // .name("scenario_id").type().intType().noDefault() diff --git a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/telemetry/parquet/ParquetProvisionerEventWriter.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/telemetry/parquet/ParquetProvisionerEventWriter.kt index 3d28860c..5d53a7bb 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/telemetry/parquet/ParquetProvisionerEventWriter.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/telemetry/parquet/ParquetProvisionerEventWriter.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,13 +20,13 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.telemetry.parquet +package org.opendc.experiments.sc20.telemetry.parquet -import com.atlarge.opendc.experiments.sc20.telemetry.ProvisionerEvent -import java.io.File import org.apache.avro.Schema import org.apache.avro.SchemaBuilder import org.apache.avro.generic.GenericData +import org.opendc.experiments.sc20.telemetry.ProvisionerEvent +import java.io.File /** * A Parquet event writer for [ProvisionerEvent]s. @@ -38,8 +36,8 @@ public class ParquetProvisionerEventWriter(path: File, bufferSize: Int) : override fun toString(): String = "provisioner-writer" - companion object { - val convert: (ProvisionerEvent, GenericData.Record) -> Unit = { event, record -> + public companion object { + private val convert: (ProvisionerEvent, GenericData.Record) -> Unit = { event, record -> record.put("timestamp", event.timestamp) record.put("host_total_count", event.totalHostCount) record.put("host_available_count", event.availableHostCount) @@ -50,9 +48,9 @@ public class ParquetProvisionerEventWriter(path: File, bufferSize: Int) : record.put("vm_failed_count", event.failedVmCount) } - val schema: Schema = SchemaBuilder + private val schema: Schema = SchemaBuilder .record("provisioner_metrics") - .namespace("com.atlarge.opendc.experiments.sc20") + .namespace("org.opendc.experiments.sc20") .fields() .name("timestamp").type().longType().noDefault() .name("host_total_count").type().intType().noDefault() diff --git a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/telemetry/parquet/ParquetRunEventWriter.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/telemetry/parquet/ParquetRunEventWriter.kt index 043e4670..74efb660 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/telemetry/parquet/ParquetRunEventWriter.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/telemetry/parquet/ParquetRunEventWriter.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,13 +20,13 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.telemetry.parquet +package org.opendc.experiments.sc20.telemetry.parquet -import com.atlarge.opendc.experiments.sc20.telemetry.RunEvent -import java.io.File import org.apache.avro.Schema import org.apache.avro.SchemaBuilder import org.apache.avro.generic.GenericData +import org.opendc.experiments.sc20.telemetry.RunEvent +import java.io.File /** * A Parquet event writer for [RunEvent]s. @@ -38,8 +36,8 @@ public class ParquetRunEventWriter(path: File, bufferSize: Int) : override fun toString(): String = "run-writer" - companion object { - val convert: (RunEvent, GenericData.Record) -> Unit = { event, record -> + public companion object { + private val convert: (RunEvent, GenericData.Record) -> Unit = { event, record -> val run = event.run val scenario = run.parent val portfolio = scenario.parent @@ -58,9 +56,9 @@ public class ParquetRunEventWriter(path: File, bufferSize: Int) : record.put("seed", run.seed) } - val schema: Schema = SchemaBuilder + private val schema: Schema = SchemaBuilder .record("runs") - .namespace("com.atlarge.opendc.experiments.sc20") + .namespace("org.opendc.experiments.sc20") .fields() .name("portfolio_id").type().intType().noDefault() .name("portfolio_name").type().stringType().noDefault() diff --git a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/trace/Sc20ParquetTraceReader.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20ParquetTraceReader.kt index 06bececf..d735ea4b 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/trace/Sc20ParquetTraceReader.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20ParquetTraceReader.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,16 +20,16 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.trace +package org.opendc.experiments.sc20.trace -import com.atlarge.opendc.compute.core.image.VmImage -import com.atlarge.opendc.compute.core.workload.IMAGE_PERF_INTERFERENCE_MODEL -import com.atlarge.opendc.compute.core.workload.PerformanceInterferenceModel -import com.atlarge.opendc.compute.core.workload.VmWorkload -import com.atlarge.opendc.experiments.sc20.experiment.model.CompositeWorkload -import com.atlarge.opendc.experiments.sc20.experiment.model.Workload -import com.atlarge.opendc.format.trace.TraceEntry -import com.atlarge.opendc.format.trace.TraceReader +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 /** @@ -42,7 +40,7 @@ import java.util.TreeSet * @param run The run to which this reader belongs. */ @OptIn(ExperimentalStdlibApi::class) -class Sc20ParquetTraceReader( +public class Sc20ParquetTraceReader( rawReaders: List<Sc20RawParquetTraceReader>, performanceInterferenceModel: Map<String, PerformanceInterferenceModel>, workload: Workload, @@ -75,13 +73,11 @@ 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/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/trace/Sc20RawParquetTraceReader.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20RawParquetTraceReader.kt index f9709b9f..9bc1a58e 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/trace/Sc20RawParquetTraceReader.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20RawParquetTraceReader.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,20 +20,20 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.trace +package org.opendc.experiments.sc20.trace -import com.atlarge.opendc.compute.core.image.FlopsHistoryFragment -import com.atlarge.opendc.compute.core.image.VmImage -import com.atlarge.opendc.compute.core.workload.VmWorkload -import com.atlarge.opendc.core.User -import com.atlarge.opendc.format.trace.TraceEntry -import com.atlarge.opendc.format.trace.TraceReader -import java.io.File -import java.util.UUID 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.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 private val logger = KotlinLogging.logger {} @@ -45,16 +43,16 @@ private val logger = KotlinLogging.logger {} * @param path The directory of the traces. */ @OptIn(ExperimentalStdlibApi::class) -class Sc20RawParquetTraceReader(private val path: File) { +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) { @@ -67,7 +65,7 @@ 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, @@ -87,7 +85,7 @@ 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() @@ -113,19 +111,20 @@ class Sc20RawParquetTraceReader(private val path: File) { val vmFragments = fragments.getValue(id).asSequence() val totalLoad = vmFragments.sumByDouble { it.usage } * 5 * 60 // avg MHz * duration = MFLOPs val vmWorkload = VmWorkload( - uid, id, + 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/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/trace/Sc20StreamingParquetTraceReader.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20StreamingParquetTraceReader.kt index 8b7b222f..edef276c 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/trace/Sc20StreamingParquetTraceReader.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20StreamingParquetTraceReader.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,24 +20,8 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.trace +package org.opendc.experiments.sc20.trace -import com.atlarge.opendc.compute.core.image.FlopsHistoryFragment -import com.atlarge.opendc.compute.core.image.VmImage -import com.atlarge.opendc.compute.core.workload.IMAGE_PERF_INTERFERENCE_MODEL -import com.atlarge.opendc.compute.core.workload.PerformanceInterferenceModel -import com.atlarge.opendc.compute.core.workload.VmWorkload -import com.atlarge.opendc.core.User -import com.atlarge.opendc.format.trace.TraceEntry -import com.atlarge.opendc.format.trace.TraceReader -import java.io.File -import java.io.Serializable -import java.util.SortedSet -import java.util.TreeSet -import java.util.UUID -import java.util.concurrent.ArrayBlockingQueue -import kotlin.concurrent.thread -import kotlin.random.Random import mu.KotlinLogging import org.apache.avro.generic.GenericData import org.apache.hadoop.fs.Path @@ -49,6 +31,22 @@ 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.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 +import java.util.TreeSet +import java.util.UUID +import java.util.concurrent.ArrayBlockingQueue +import kotlin.concurrent.thread +import kotlin.random.Random private val logger = KotlinLogging.logger {} @@ -59,7 +57,7 @@ private val logger = KotlinLogging.logger {} * @param performanceInterferenceModel The performance model covering the workload in the VM trace. */ @OptIn(ExperimentalStdlibApi::class) -class Sc20StreamingParquetTraceReader( +public class Sc20StreamingParquetTraceReader( traceFile: File, performanceInterferenceModel: PerformanceInterferenceModel, selectedVms: List<String>, @@ -73,7 +71,7 @@ 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 @@ -82,16 +80,19 @@ class Sc20StreamingParquetTraceReader( if (selectedVms.isEmpty()) null else - FilterCompat.get(FilterApi.userDefined(FilterApi.binaryColumn("id"), - SelectedVmFilter( - TreeSet(selectedVms) + FilterCompat.get( + FilterApi.userDefined( + FilterApi.binaryColumn("id"), + SelectedVmFilter( + TreeSet(selectedVms) + ) ) - )) + ) /** * 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. @@ -118,7 +119,7 @@ class Sc20StreamingParquetTraceReader( val cpuUsage = record["cpuUsage"] as Double val flops = record["flops"] as Long - val fragment = FlopsHistoryFragment( + val fragment = SimTraceWorkload.Fragment( tick, flops, duration, @@ -138,12 +139,12 @@ 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) { @@ -166,7 +167,7 @@ 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() @@ -199,11 +200,11 @@ 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> { - repeat@while (true) { + val fragments = sequence { + repeat@ while (true) { if (externalBuffer.isEmpty()) { if (hasNext) { pull(buffers) @@ -219,7 +220,7 @@ class Sc20StreamingParquetTraceReader( for (fragment in internalBuffer) { yield(fragment) - if (fragment.tick >= endTime) { + if (fragment.time >= endTime) { break@repeat } } @@ -235,15 +236,18 @@ class Sc20StreamingParquetTraceReader( Random(random.nextInt()) ) val vmWorkload = VmWorkload( - uid, "VM Workload $id", + 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/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/trace/Sc20TraceConverter.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20TraceConverter.kt index 56ddbb6d..bb2a75ee 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/trace/Sc20TraceConverter.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/Sc20TraceConverter.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,9 +20,8 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.trace +package org.opendc.experiments.sc20.trace -import com.atlarge.opendc.format.trace.sc20.Sc20VmPlacementReader import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.parameters.arguments.argument import com.github.ajalt.clikt.parameters.groups.OptionGroup @@ -37,12 +34,6 @@ import com.github.ajalt.clikt.parameters.options.required import com.github.ajalt.clikt.parameters.options.split import com.github.ajalt.clikt.parameters.types.file import com.github.ajalt.clikt.parameters.types.long -import java.io.BufferedReader -import java.io.File -import java.io.FileReader -import java.util.Random -import kotlin.math.max -import kotlin.math.min import me.tongfei.progressbar.ProgressBar import org.apache.avro.Schema import org.apache.avro.SchemaBuilder @@ -51,11 +42,18 @@ import org.apache.hadoop.fs.Path import org.apache.parquet.avro.AvroParquetWriter import org.apache.parquet.hadoop.ParquetWriter import org.apache.parquet.hadoop.metadata.CompressionCodecName +import org.opendc.format.trace.sc20.Sc20VmPlacementReader +import java.io.BufferedReader +import java.io.File +import java.io.FileReader +import java.util.Random +import kotlin.math.max +import kotlin.math.min /** * Represents the command for converting traces */ -class TraceConverterCli : CliktCommand(name = "trace-converter") { +public class TraceConverterCli : CliktCommand(name = "trace-converter") { /** * The directory where the trace should be stored. */ @@ -72,7 +70,7 @@ class TraceConverterCli : CliktCommand(name = "trace-converter") { /** * The input type of the trace. */ - val type by option("-t", "--type", help = "input type of trace").groupChoice( + private val type by option("-t", "--type", help = "input type of trace").groupChoice( "solvinity" to SolvinityConversion(), "bitbrains" to BitbrainsConversion(), "azure" to AzureConversion() @@ -81,7 +79,7 @@ class TraceConverterCli : CliktCommand(name = "trace-converter") { override fun run() { val metaSchema = SchemaBuilder .record("meta") - .namespace("com.atlarge.opendc.format.sc20") + .namespace("org.opendc.format.sc20") .fields() .name("id").type().stringType().noDefault() .name("submissionTime").type().longType().noDefault() @@ -91,7 +89,7 @@ class TraceConverterCli : CliktCommand(name = "trace-converter") { .endRecord() val schema = SchemaBuilder .record("trace") - .namespace("com.atlarge.opendc.format.sc20") + .namespace("org.opendc.format.sc20") .fields() .name("id").type().stringType().noDefault() .name("time").type().longType().noDefault() @@ -151,22 +149,22 @@ class TraceConverterCli : CliktCommand(name = "trace-converter") { /** * The supported trace conversions. */ -sealed class TraceConversion(name: String) : OptionGroup(name) { +public sealed class TraceConversion(name: String) : OptionGroup(name) { /** * Read the fragments of the trace. */ - abstract fun read( + public abstract fun read( traceDirectory: File, metaSchema: Schema, metaWriter: ParquetWriter<GenericData.Record> ): MutableList<Fragment> } -class SolvinityConversion : TraceConversion("Solvinity") { - val clusters by option() +public class SolvinityConversion : TraceConversion("Solvinity") { + private val clusters by option() .split(",") - val vmPlacements by option("--vm-placements", help = "file containing the VM placements") + private val vmPlacements by option("--vm-placements", help = "file containing the VM placements") .file(canBeDir = false) .convert { it.inputStream().buffered().use { Sc20VmPlacementReader(it).construct() } } .required() @@ -189,11 +187,11 @@ 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()) { @@ -214,7 +212,7 @@ class SolvinityConversion : TraceConversion("Solvinity") { if (timestamp < minTimestamp) { minTimestamp = timestamp } - return@forEach + return@file } } } @@ -231,13 +229,13 @@ 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 { @@ -263,7 +261,8 @@ class SolvinityConversion : TraceConversion("Solvinity") { continue } - val timestamp = (values[timestampCol].trim().toLong() - 5 * 60) * 1000L - minTimestamp + val timestamp = + (values[timestampCol].trim().toLong() - 5 * 60) * 1000L - minTimestamp if (begin > timestamp || timestamp > end) { continue } @@ -336,7 +335,7 @@ class SolvinityConversion : TraceConversion("Solvinity") { /** * Conversion of the Bitbrains public trace. */ -class BitbrainsConversion : TraceConversion("Bitbrains") { +public class BitbrainsConversion : TraceConversion("Bitbrains") { override fun read( traceDirectory: File, metaSchema: Schema, @@ -354,13 +353,13 @@ 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 { @@ -384,7 +383,8 @@ class BitbrainsConversion : TraceConversion("Bitbrains") { val timestamp = (values[timestampCol].trim().toLong() - 5 * 60) * 1000L cores = values[coreCol].trim().toInt() - requiredMemory = max(requiredMemory, values[provisionedMemoryCol].trim().toDouble().toLong()) + requiredMemory = + max(requiredMemory, values[provisionedMemoryCol].trim().toDouble().toLong()) maxCores = max(maxCores, cores) minTime = min(minTime, timestamp) val cpuUsage = values[cpuUsageCol].trim().toDouble() // MHz @@ -447,8 +447,8 @@ class BitbrainsConversion : TraceConversion("Bitbrains") { /** * Conversion of the Azure public VM trace. */ -class AzureConversion : TraceConversion("Azure") { - val seed by option(help = "seed for trace sampling") +public class AzureConversion : TraceConversion("Azure") { + private val seed by option(help = "seed for trace sampling") .long() .default(0) @@ -604,18 +604,18 @@ class AzureConversion : TraceConversion("Azure") { } } -data class Fragment( - val id: String, - val tick: Long, - val flops: Long, - val duration: Long, - val usage: Double, - val cores: Int +public data class Fragment( + public val id: String, + public val tick: Long, + public val flops: Long, + public val duration: Long, + public val usage: Double, + public val cores: Int ) -class VmInfo(val cores: Int, val requiredMemory: Long, var minTime: Long, var maxTime: Long) +public class VmInfo(public val cores: Int, public val requiredMemory: Long, public var minTime: Long, public var maxTime: Long) /** * A script to convert a trace in text format into a Parquet trace. */ -fun main(args: Array<String>) = TraceConverterCli().main(args) +public fun main(args: Array<String>): Unit = TraceConverterCli().main(args) diff --git a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/trace/WorkloadSampler.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/WorkloadSampler.kt index a46bb3e6..a8b83aef 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/kotlin/com/atlarge/opendc/experiments/sc20/trace/WorkloadSampler.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/kotlin/org/opendc/experiments/sc20/trace/WorkloadSampler.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,24 +20,24 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20.trace +package org.opendc.experiments.sc20.trace -import com.atlarge.opendc.compute.core.image.VmImage -import com.atlarge.opendc.compute.core.workload.VmWorkload -import com.atlarge.opendc.experiments.sc20.experiment.model.CompositeWorkload -import com.atlarge.opendc.experiments.sc20.experiment.model.SamplingStrategy -import com.atlarge.opendc.experiments.sc20.experiment.model.Workload -import com.atlarge.opendc.format.trace.TraceEntry +import mu.KotlinLogging +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 +import org.opendc.format.trace.TraceEntry import java.util.* import kotlin.random.Random -import mu.KotlinLogging private val logger = KotlinLogging.logger {} /** * Sample the workload for the specified [run]. */ -fun sampleWorkload( +public fun sampleWorkload( trace: List<TraceEntry<VmWorkload>>, workload: Workload, subWorkload: Workload, @@ -59,7 +57,7 @@ fun sampleWorkload( /** * Sample a regular (non-HPC) workload. */ -fun sampleRegularWorkload( +public fun sampleRegularWorkload( trace: List<TraceEntry<VmWorkload>>, workload: Workload, subWorkload: Workload, @@ -94,7 +92,7 @@ fun sampleRegularWorkload( /** * Sample a HPC workload. */ -fun sampleHpcWorkload( +public fun sampleHpcWorkload( trace: List<TraceEntry<VmWorkload>>, workload: Workload, seed: Int, @@ -145,7 +143,6 @@ 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) { @@ -199,16 +196,15 @@ 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) } -private class VmTraceEntry(override val workload: VmWorkload, override val submissionTime: Long) : TraceEntry<VmWorkload> +private class VmTraceEntry(override val workload: VmWorkload, override val submissionTime: Long) : + TraceEntry<VmWorkload> diff --git a/simulator/opendc/opendc-experiments-sc20/src/main/resources/log4j2.xml b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/resources/log4j2.xml index 6906bfc3..8029092e 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/main/resources/log4j2.xml +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/main/resources/log4j2.xml @@ -26,20 +26,17 @@ <Configuration status="WARN"> <Appenders> <Console name="Console" target="SYSTEM_OUT"> - <PatternLayout pattern="%d{HH:mm:ss.SSS} [%highlight{%-5level}] %logger{36} - %msg%n" disableAnsi="false" /> + <PatternLayout pattern="%d{HH:mm:ss.SSS} [%highlight{%-5level}] %logger{36} - %msg%n" disableAnsi="false"/> </Console> </Appenders> <Loggers> - <Logger name="com.atlarge.odcsim" level="info" additivity="false"> + <Logger name="org.opendc" level="debug" additivity="false"> <AppenderRef ref="Console"/> </Logger> - <Logger name="com.atlarge.opendc" level="warn" additivity="false"> + <Logger name="org.opendc.experiments.sc20" level="info" additivity="false"> <AppenderRef ref="Console"/> </Logger> - <Logger name="com.atlarge.opendc.experiments.sc20" level="info" additivity="false"> - <AppenderRef ref="Console"/> - </Logger> - <Logger name="com.atlarge.opendc.experiments.sc20.trace" level="debug" additivity="false"> + <Logger name="org.opendc.experiments.sc20.trace" level="debug" additivity="false"> <AppenderRef ref="Console"/> </Logger> <Logger name="org.apache.hadoop" level="warn" additivity="false"> diff --git a/simulator/opendc/opendc-experiments-sc20/src/test/kotlin/com/atlarge/opendc/experiments/sc20/Sc20IntegrationTest.kt b/simulator/opendc-experiments/opendc-experiments-sc20/src/test/kotlin/org/opendc/experiments/sc20/Sc20IntegrationTest.kt index a79e9a5a..9c44edfc 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/test/kotlin/com/atlarge/opendc/experiments/sc20/Sc20IntegrationTest.kt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/test/kotlin/org/opendc/experiments/sc20/Sc20IntegrationTest.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,52 +20,51 @@ * SOFTWARE. */ -package com.atlarge.opendc.experiments.sc20 - -import com.atlarge.odcsim.Domain -import com.atlarge.odcsim.SimulationEngine -import com.atlarge.odcsim.SimulationEngineProvider -import com.atlarge.opendc.compute.core.Server -import com.atlarge.opendc.compute.core.workload.VmWorkload -import com.atlarge.opendc.compute.virt.service.SimpleVirtProvisioningService -import com.atlarge.opendc.compute.virt.service.allocation.AvailableCoreMemoryAllocationPolicy -import com.atlarge.opendc.experiments.sc20.experiment.attachMonitor -import com.atlarge.opendc.experiments.sc20.experiment.createFailureDomain -import com.atlarge.opendc.experiments.sc20.experiment.createProvisioner -import com.atlarge.opendc.experiments.sc20.experiment.model.Workload -import com.atlarge.opendc.experiments.sc20.experiment.monitor.ExperimentMonitor -import com.atlarge.opendc.experiments.sc20.experiment.processTrace -import com.atlarge.opendc.experiments.sc20.trace.Sc20ParquetTraceReader -import com.atlarge.opendc.experiments.sc20.trace.Sc20RawParquetTraceReader -import com.atlarge.opendc.format.environment.EnvironmentReader -import com.atlarge.opendc.format.environment.sc20.Sc20ClusterEnvironmentReader -import com.atlarge.opendc.format.trace.TraceReader -import java.io.File -import java.util.ServiceLoader +package org.opendc.experiments.sc20 + +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.cancel import kotlinx.coroutines.channels.Channel import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.TestCoroutineScope import org.junit.jupiter.api.AfterEach -import org.junit.jupiter.api.Assertions.assertAll 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.Server +import org.opendc.compute.core.workload.VmWorkload +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 +import org.opendc.experiments.sc20.experiment.model.Workload +import org.opendc.experiments.sc20.experiment.monitor.ExperimentMonitor +import org.opendc.experiments.sc20.experiment.processTrace +import org.opendc.experiments.sc20.trace.Sc20ParquetTraceReader +import org.opendc.experiments.sc20.trace.Sc20RawParquetTraceReader +import org.opendc.format.environment.EnvironmentReader +import org.opendc.format.environment.sc20.Sc20ClusterEnvironmentReader +import org.opendc.format.trace.TraceReader +import org.opendc.simulator.utils.DelayControllerClockAdapter +import java.io.File +import java.time.Clock /** * An integration test suite for the SC20 experiments. */ +@OptIn(ExperimentalCoroutinesApi::class) class Sc20IntegrationTest { /** - * The simulation engine to use. + * The [TestCoroutineScope] to use. */ - private lateinit var simulationEngine: SimulationEngine + private lateinit var testScope: TestCoroutineScope /** - * The root simulation domain to run in. + * The simulation clock to use. */ - private lateinit var root: Domain + private lateinit var clock: Clock /** * The monitor used to keep track of the metrics. @@ -79,9 +76,9 @@ class Sc20IntegrationTest { */ @BeforeEach fun setUp() { - val provider = ServiceLoader.load(SimulationEngineProvider::class.java).first() - simulationEngine = provider("test") - root = simulationEngine.newDomain("root") + testScope = TestCoroutineScope() + clock = DelayControllerClockAdapter(testScope) + monitor = TestExperimentReporter() } @@ -89,9 +86,7 @@ class Sc20IntegrationTest { * Tear down the experimental environment. */ @AfterEach - fun tearDown() = runBlocking { - simulationEngine.terminate() - } + fun tearDown() = testScope.cleanupTestCoroutines() @Test fun smoke() { @@ -101,11 +96,12 @@ class Sc20IntegrationTest { val allocationPolicy = AvailableCoreMemoryAllocationPolicy() val traceReader = createTestTraceReader() val environmentReader = createTestEnvironmentReader() - lateinit var scheduler: SimpleVirtProvisioningService + lateinit var scheduler: SimVirtProvisioningService - root.launch { + testScope.launch { val res = createProvisioner( - root, + this, + clock, environmentReader, allocationPolicy ) @@ -115,6 +111,8 @@ class Sc20IntegrationTest { val failureDomain = if (failures) { println("ENABLING failures") createFailureDomain( + this, + clock, seed, 24.0 * 7, bareMetalProvisioner, @@ -124,8 +122,10 @@ class Sc20IntegrationTest { null } - attachMonitor(scheduler, monitor) + attachMonitor(this, clock, scheduler, monitor) processTrace( + this, + clock, traceReader, scheduler, chan, @@ -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,18 +159,21 @@ class Sc20IntegrationTest { val allocationPolicy = AvailableCoreMemoryAllocationPolicy() val traceReader = createTestTraceReader(0.5, seed) val environmentReader = createTestEnvironmentReader("single") - lateinit var scheduler: SimpleVirtProvisioningService + lateinit var scheduler: SimVirtProvisioningService - root.launch { + testScope.launch { val res = createProvisioner( - root, + this, + clock, environmentReader, allocationPolicy ) scheduler = res.second - attachMonitor(scheduler, monitor) + attachMonitor(this, clock, scheduler, monitor) processTrace( + this, + clock, traceReader, scheduler, chan, @@ -195,9 +200,7 @@ class Sc20IntegrationTest { /** * Run the simulation. */ - private fun runSimulation() = runBlocking { - simulationEngine.run() - } + private fun runSimulation() = testScope.advanceUntilIdle() /** * Obtain the trace reader for the test. diff --git a/simulator/opendc/opendc-experiments-sc20/src/test/resources/env/single.txt b/simulator/opendc-experiments/opendc-experiments-sc20/src/test/resources/env/single.txt index 53b3c2d7..53b3c2d7 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/test/resources/env/single.txt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/test/resources/env/single.txt diff --git a/simulator/opendc/opendc-experiments-sc20/src/test/resources/env/topology.txt b/simulator/opendc-experiments/opendc-experiments-sc20/src/test/resources/env/topology.txt index 6b347bff..6b347bff 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/test/resources/env/topology.txt +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/test/resources/env/topology.txt diff --git a/simulator/opendc/opendc-experiments-sc20/src/test/resources/trace/meta.parquet b/simulator/opendc-experiments/opendc-experiments-sc20/src/test/resources/trace/meta.parquet Binary files differindex ce7a812c..ce7a812c 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/test/resources/trace/meta.parquet +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/test/resources/trace/meta.parquet diff --git a/simulator/opendc/opendc-experiments-sc20/src/test/resources/trace/trace.parquet b/simulator/opendc-experiments/opendc-experiments-sc20/src/test/resources/trace/trace.parquet Binary files differindex 1d7ce882..1d7ce882 100644 --- a/simulator/opendc/opendc-experiments-sc20/src/test/resources/trace/trace.parquet +++ b/simulator/opendc-experiments/opendc-experiments-sc20/src/test/resources/trace/trace.parquet diff --git a/simulator/opendc/opendc-format/build.gradle.kts b/simulator/opendc-format/build.gradle.kts index 4414b638..30aafc90 100644 --- a/simulator/opendc/opendc-format/build.gradle.kts +++ b/simulator/opendc-format/build.gradle.kts @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 atlarge-research + * Copyright (c) 2019 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 @@ -30,13 +28,22 @@ plugins { } dependencies { - api(project(":opendc:opendc-core")) - api(project(":opendc:opendc-compute")) - api(project(":opendc:opendc-workflows")) - api("com.fasterxml.jackson.module:jackson-module-kotlin:2.9.8") - implementation(kotlin("stdlib")) + api(project(":opendc-core")) + api(project(":opendc-compute:opendc-compute-core")) + api(project(":opendc-workflows")) + 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")) + implementation("org.apache.parquet:parquet-avro:1.11.0") + implementation("org.apache.hadoop:hadoop-client:3.2.1") { + exclude(group = "org.slf4j", module = "slf4j-log4j12") + exclude(group = "log4j") + } + 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/opendc-format/src/main/kotlin/com/atlarge/opendc/format/environment/EnvironmentReader.kt b/simulator/opendc-format/src/main/kotlin/org/opendc/format/environment/EnvironmentReader.kt index 1c3f70e6..1f73bb61 100644 --- a/simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/environment/EnvironmentReader.kt +++ b/simulator/opendc-format/src/main/kotlin/org/opendc/format/environment/EnvironmentReader.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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,18 +20,19 @@ * SOFTWARE. */ -package com.atlarge.opendc.format.environment +package org.opendc.format.environment -import com.atlarge.odcsim.Domain -import com.atlarge.opendc.core.Environment +import kotlinx.coroutines.CoroutineScope +import org.opendc.core.Environment import java.io.Closeable +import java.time.Clock /** * An interface for reading descriptions of topology environments into memory as [Environment]. */ -interface EnvironmentReader : Closeable { +public interface EnvironmentReader : Closeable { /** - * Construct an [Environment] in the specified domain. + * Construct an [Environment] in the specified [CoroutineScope]. */ - suspend fun construct(dom: Domain): Environment + public suspend fun construct(coroutineScope: CoroutineScope, clock: Clock): Environment } diff --git a/simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/environment/sc18/Model.kt b/simulator/opendc-format/src/main/kotlin/org/opendc/format/environment/sc18/Model.kt index f3e70982..c313467f 100644 --- a/simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/environment/sc18/Model.kt +++ b/simulator/opendc-format/src/main/kotlin/org/opendc/format/environment/sc18/Model.kt @@ -1,4 +1,26 @@ -package com.atlarge.opendc.format.environment.sc18 +/* + * 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.format.environment.sc18 import com.fasterxml.jackson.annotation.JsonSubTypes import com.fasterxml.jackson.annotation.JsonTypeInfo diff --git a/simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/environment/sc18/Sc18EnvironmentReader.kt b/simulator/opendc-format/src/main/kotlin/org/opendc/format/environment/sc18/Sc18EnvironmentReader.kt index a9aa3337..2e3e4a73 100644 --- a/simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/environment/sc18/Sc18EnvironmentReader.kt +++ b/simulator/opendc-format/src/main/kotlin/org/opendc/format/environment/sc18/Sc18EnvironmentReader.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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,25 +20,27 @@ * SOFTWARE. */ -package com.atlarge.opendc.format.environment.sc18 +package org.opendc.format.environment.sc18 -import com.atlarge.odcsim.Domain -import com.atlarge.opendc.compute.core.MemoryUnit -import com.atlarge.opendc.compute.core.ProcessingNode -import com.atlarge.opendc.compute.core.ProcessingUnit -import com.atlarge.opendc.compute.metal.driver.SimpleBareMetalDriver -import com.atlarge.opendc.compute.metal.service.ProvisioningService -import com.atlarge.opendc.compute.metal.service.SimpleProvisioningService -import com.atlarge.opendc.core.Environment -import com.atlarge.opendc.core.Platform -import com.atlarge.opendc.core.Zone -import com.atlarge.opendc.core.services.ServiceRegistry -import com.atlarge.opendc.format.environment.EnvironmentReader 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.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.util.UUID +import java.time.Clock +import java.util.* /** * A parser for the JSON experiment setup files used for the SC18 paper: "A Reference Architecture for Topology @@ -49,15 +49,13 @@ import java.util.UUID * @param input The input stream to read from. * @param mapper The Jackson object mapper to use. */ -class Sc18EnvironmentReader(input: InputStream, mapper: ObjectMapper = jacksonObjectMapper()) : EnvironmentReader { +public class Sc18EnvironmentReader(input: InputStream, mapper: ObjectMapper = jacksonObjectMapper()) : EnvironmentReader { /** * The environment that was read from the file. */ private val setup: Setup = mapper.readValue(input) - override suspend fun construct(dom: Domain): Environment { - val provisioningDomain = dom.newDomain("provisioner") - + override suspend fun construct(coroutineScope: CoroutineScope, clock: Clock): Environment { var counter = 0 val nodes = setup.rooms.flatMap { room -> room.objects.flatMap { roomObject -> @@ -77,13 +75,13 @@ class Sc18EnvironmentReader(input: InputStream, mapper: ObjectMapper = jacksonOb else -> throw IllegalArgumentException("The cpu id $id is not recognized") } } - SimpleBareMetalDriver( - dom.newDomain("node-$counter"), + SimBareMetalDriver( + coroutineScope, + clock, UUID.randomUUID(), "node-${counter++}", emptyMap(), - cores, - listOf(MemoryUnit("", "", 2300.0, 16000)) + SimMachineModel(cores, listOf(MemoryUnit("", "", 2300.0, 16000))) ) } } @@ -91,14 +89,16 @@ class Sc18EnvironmentReader(input: InputStream, mapper: ObjectMapper = jacksonOb } } - val provisioningService = SimpleProvisioningService(provisioningDomain) + val provisioningService = SimpleProvisioningService() for (node in nodes) { provisioningService.create(node) } val serviceRegistry = ServiceRegistry().put(ProvisioningService, provisioningService) val platform = Platform( - UUID.randomUUID(), "sc18-platform", listOf( + UUID.randomUUID(), + "sc18-platform", + listOf( Zone(UUID.randomUUID(), "zone", serviceRegistry) ) ) diff --git a/simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/environment/sc20/Model.kt b/simulator/opendc-format/src/main/kotlin/org/opendc/format/environment/sc20/Model.kt index 0a8f1c14..58af8453 100644 --- a/simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/environment/sc20/Model.kt +++ b/simulator/opendc-format/src/main/kotlin/org/opendc/format/environment/sc20/Model.kt @@ -1,4 +1,26 @@ -package com.atlarge.opendc.format.environment.sc20 +/* + * 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.format.environment.sc20 import com.fasterxml.jackson.annotation.JsonSubTypes import com.fasterxml.jackson.annotation.JsonTypeInfo diff --git a/simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/environment/sc20/Sc20ClusterEnvironmentReader.kt b/simulator/opendc-format/src/main/kotlin/org/opendc/format/environment/sc20/Sc20ClusterEnvironmentReader.kt index e34ee2dc..b4c71c4e 100644 --- a/simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/environment/sc20/Sc20ClusterEnvironmentReader.kt +++ b/simulator/opendc-format/src/main/kotlin/org/opendc/format/environment/sc20/Sc20ClusterEnvironmentReader.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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,41 +20,42 @@ * SOFTWARE. */ -package com.atlarge.opendc.format.environment.sc20 - -import com.atlarge.odcsim.Domain -import com.atlarge.opendc.compute.core.MemoryUnit -import com.atlarge.opendc.compute.core.ProcessingNode -import com.atlarge.opendc.compute.core.ProcessingUnit -import com.atlarge.opendc.compute.metal.NODE_CLUSTER -import com.atlarge.opendc.compute.metal.driver.SimpleBareMetalDriver -import com.atlarge.opendc.compute.metal.power.LinearLoadPowerModel -import com.atlarge.opendc.compute.metal.service.ProvisioningService -import com.atlarge.opendc.compute.metal.service.SimpleProvisioningService -import com.atlarge.opendc.core.Environment -import com.atlarge.opendc.core.Platform -import com.atlarge.opendc.core.Zone -import com.atlarge.opendc.core.services.ServiceRegistry -import com.atlarge.opendc.format.environment.EnvironmentReader +package org.opendc.format.environment.sc20 + +import kotlinx.coroutines.CoroutineScope +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 -import java.util.Random -import java.util.UUID +import java.time.Clock +import java.util.* /** * A [EnvironmentReader] for the internal environment format. * * @param environmentFile The file describing the physical cluster. */ -class Sc20ClusterEnvironmentReader( +public class Sc20ClusterEnvironmentReader( private val input: InputStream ) : EnvironmentReader { - constructor(file: File) : this(FileInputStream(file)) + public constructor(file: File) : this(FileInputStream(file)) @Suppress("BlockingMethodInNonBlockingContext") - override suspend fun construct(dom: Domain): Environment { + override suspend fun construct(coroutineScope: CoroutineScope, clock: Clock): Environment { var clusterIdCol = 0 var speedCol = 0 var numberOfHostsCol = 0 @@ -70,7 +69,7 @@ class Sc20ClusterEnvironmentReader( var memoryPerHost: Long var coresPerHost: Int - val nodes = mutableListOf<SimpleBareMetalDriver>() + val nodes = mutableListOf<SimBareMetalDriver>() val random = Random(0) input.bufferedReader().use { reader -> @@ -104,18 +103,21 @@ class Sc20ClusterEnvironmentReader( repeat(numberOfHosts) { nodes.add( - SimpleBareMetalDriver( - dom.newDomain("node-$clusterId-$it"), + 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) ) ) @@ -123,7 +125,7 @@ class Sc20ClusterEnvironmentReader( } } - val provisioningService = SimpleProvisioningService(dom.newDomain("provisioner")) + val provisioningService = SimpleProvisioningService() for (node in nodes) { provisioningService.create(node) } @@ -131,7 +133,9 @@ class Sc20ClusterEnvironmentReader( val serviceRegistry = ServiceRegistry().put(ProvisioningService, provisioningService) val platform = Platform( - UUID.randomUUID(), "sc20-platform", listOf( + UUID.randomUUID(), + "sc20-platform", + listOf( Zone(UUID.randomUUID(), "zone", serviceRegistry) ) ) diff --git a/simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/environment/sc20/Sc20EnvironmentReader.kt b/simulator/opendc-format/src/main/kotlin/org/opendc/format/environment/sc20/Sc20EnvironmentReader.kt index 4b5d6fb7..94237cb9 100644 --- a/simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/environment/sc20/Sc20EnvironmentReader.kt +++ b/simulator/opendc-format/src/main/kotlin/org/opendc/format/environment/sc20/Sc20EnvironmentReader.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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,26 +20,28 @@ * SOFTWARE. */ -package com.atlarge.opendc.format.environment.sc20 +package org.opendc.format.environment.sc20 -import com.atlarge.odcsim.Domain -import com.atlarge.opendc.compute.core.MemoryUnit -import com.atlarge.opendc.compute.core.ProcessingNode -import com.atlarge.opendc.compute.core.ProcessingUnit -import com.atlarge.opendc.compute.metal.driver.SimpleBareMetalDriver -import com.atlarge.opendc.compute.metal.power.LinearLoadPowerModel -import com.atlarge.opendc.compute.metal.service.ProvisioningService -import com.atlarge.opendc.compute.metal.service.SimpleProvisioningService -import com.atlarge.opendc.core.Environment -import com.atlarge.opendc.core.Platform -import com.atlarge.opendc.core.Zone -import com.atlarge.opendc.core.services.ServiceRegistry -import com.atlarge.opendc.format.environment.EnvironmentReader 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.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.util.UUID +import java.time.Clock +import java.util.* /** * A parser for the JSON experiment setup files used for the SC20 paper. @@ -49,13 +49,13 @@ import java.util.UUID * @param input The input stream to read from. * @param mapper The Jackson object mapper to use. */ -class Sc20EnvironmentReader(input: InputStream, mapper: ObjectMapper = jacksonObjectMapper()) : EnvironmentReader { +public class Sc20EnvironmentReader(input: InputStream, mapper: ObjectMapper = jacksonObjectMapper()) : EnvironmentReader { /** * The environment that was read from the file. */ private val setup: Setup = mapper.readValue(input) - override suspend fun construct(dom: Domain): Environment { + override suspend fun construct(coroutineScope: CoroutineScope, clock: Clock): Environment { var counter = 0 val nodes = setup.rooms.flatMap { room -> room.objects.flatMap { roomObject -> @@ -81,16 +81,16 @@ class Sc20EnvironmentReader(input: InputStream, mapper: ObjectMapper = jacksonOb else -> throw IllegalArgumentException("The cpu id $id is not recognized") } } - SimpleBareMetalDriver( - dom.newDomain("node-$counter"), + 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) ) } @@ -99,7 +99,7 @@ class Sc20EnvironmentReader(input: InputStream, mapper: ObjectMapper = jacksonOb } } - val provisioningService = SimpleProvisioningService(dom.newDomain("provisioner")) + val provisioningService = SimpleProvisioningService() for (node in nodes) { provisioningService.create(node) } @@ -107,7 +107,9 @@ class Sc20EnvironmentReader(input: InputStream, mapper: ObjectMapper = jacksonOb val serviceRegistry = ServiceRegistry().put(ProvisioningService, provisioningService) val platform = Platform( - UUID.randomUUID(), "sc20-platform", listOf( + UUID.randomUUID(), + "sc20-platform", + listOf( Zone(UUID.randomUUID(), "zone", serviceRegistry) ) ) diff --git a/simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/PerformanceInterferenceModelReader.kt b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/PerformanceInterferenceModelReader.kt index 407bc0b4..f30e64cf 100644 --- a/simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/PerformanceInterferenceModelReader.kt +++ b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/PerformanceInterferenceModelReader.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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,18 +20,18 @@ * SOFTWARE. */ -package com.atlarge.opendc.format.trace +package org.opendc.format.trace -import com.atlarge.opendc.compute.core.workload.PerformanceInterferenceModel +import org.opendc.simulator.compute.interference.PerformanceInterferenceModel import java.io.Closeable import kotlin.random.Random /** * An interface for reading descriptions of performance interference models into memory. */ -interface PerformanceInterferenceModelReader : Closeable { +public interface PerformanceInterferenceModelReader : Closeable { /** * Construct a [PerformanceInterferenceModel]. */ - fun construct(random: Random): Map<String, PerformanceInterferenceModel> + public fun construct(random: Random): Map<String, PerformanceInterferenceModel> } diff --git a/simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/TraceEntry.kt b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/TraceEntry.kt index d4ad33f7..ec547e84 100644 --- a/simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/TraceEntry.kt +++ b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/TraceEntry.kt @@ -22,33 +22,33 @@ * SOFTWARE. */ -package com.atlarge.opendc.format.trace +package org.opendc.format.trace -import com.atlarge.opendc.core.workload.Workload +import org.opendc.core.workload.Workload /** * An entry in a workload trace. * * @param T The shape of the workload in this entry. */ -interface TraceEntry<T : Workload> { +public interface TraceEntry<T : Workload> { /** * The time of submission of the workload. */ - val submissionTime: Long + public val submissionTime: Long /** * The workload in this trace entry. */ - val workload: T + public val workload: T /** * Extract the submission time from this entry. */ - operator fun component1() = submissionTime + public operator fun component1(): Long = submissionTime /** * Extract the workload from this entry. */ - operator fun component2() = workload + public operator fun component2(): T = workload } diff --git a/simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/TraceReader.kt b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/TraceReader.kt index 6d29cdb4..a0beec3e 100644 --- a/simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/TraceReader.kt +++ b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/TraceReader.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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,9 +20,9 @@ * SOFTWARE. */ -package com.atlarge.opendc.format.trace +package org.opendc.format.trace -import com.atlarge.opendc.core.workload.Workload +import org.opendc.core.workload.Workload import java.io.Closeable /** @@ -34,4 +32,4 @@ import java.io.Closeable * * @param T The shape of the workloads supported by this reader. */ -interface TraceReader<T : Workload> : Iterator<TraceEntry<T>>, Closeable +public interface TraceReader<T : Workload> : Iterator<TraceEntry<T>>, Closeable diff --git a/simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/TraceWriter.kt b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/TraceWriter.kt index 94ee6f31..54fb6214 100644 --- a/simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/TraceWriter.kt +++ b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/TraceWriter.kt @@ -22,9 +22,9 @@ * SOFTWARE. */ -package com.atlarge.opendc.format.trace +package org.opendc.format.trace -import com.atlarge.opendc.core.workload.Workload +import org.opendc.core.workload.Workload import java.io.Closeable /** @@ -32,7 +32,7 @@ import java.io.Closeable * * @param T The type of [Workload] supported by this writer. */ -interface TraceWriter<T : Workload> : Closeable { +public interface TraceWriter<T : Workload> : Closeable { /** * Write an entry to the trace. * @@ -41,5 +41,5 @@ interface TraceWriter<T : Workload> : Closeable { * @param submissionTime The time of submission of the workload. * @param workload The workload to write to the trace. */ - fun write(submissionTime: Long, workload: T) + public fun write(submissionTime: Long, workload: T) } diff --git a/simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/VmPlacementReader.kt b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/VmPlacementReader.kt index 7caebb76..6861affe 100644 --- a/simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/VmPlacementReader.kt +++ b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/VmPlacementReader.kt @@ -22,16 +22,16 @@ * SOFTWARE. */ -package com.atlarge.opendc.format.trace +package org.opendc.format.trace import java.io.Closeable /** * An interface for reading VM placement data into memory. */ -interface VmPlacementReader : Closeable { +public interface VmPlacementReader : Closeable { /** * Construct a map of VMs to clusters. */ - fun construct(): Map<String, String> + public fun construct(): Map<String, String> } diff --git a/simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/bitbrains/BitbrainsTraceReader.kt b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/bitbrains/BitbrainsTraceReader.kt index 1cabc8bc..9353ef28 100644 --- a/simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/bitbrains/BitbrainsTraceReader.kt +++ b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/bitbrains/BitbrainsTraceReader.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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,20 +20,20 @@ * SOFTWARE. */ -package com.atlarge.opendc.format.trace.bitbrains +package org.opendc.format.trace.bitbrains -import com.atlarge.opendc.compute.core.image.FlopsHistoryFragment -import com.atlarge.opendc.compute.core.image.VmImage -import com.atlarge.opendc.compute.core.workload.IMAGE_PERF_INTERFERENCE_MODEL -import com.atlarge.opendc.compute.core.workload.PerformanceInterferenceModel -import com.atlarge.opendc.compute.core.workload.VmWorkload -import com.atlarge.opendc.core.User -import com.atlarge.opendc.format.trace.TraceEntry -import com.atlarge.opendc.format.trace.TraceReader +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 -import java.util.UUID +import java.util.* /** * A [TraceReader] for the public VM workload trace format. @@ -43,7 +41,7 @@ import java.util.UUID * @param traceDirectory The directory of the traces. * @param performanceInterferenceModel The performance model covering the workload in the VM trace. */ -class BitbrainsTraceReader( +public class BitbrainsTraceReader( traceDirectory: File, performanceInterferenceModel: PerformanceInterferenceModel ) : TraceReader<VmWorkload> { @@ -68,7 +66,7 @@ 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 @@ -101,15 +99,23 @@ 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(timestamp, flops, traceInterval, cpuUsage, cores)) + flopsHistory.add( + SimTraceWorkload.Fragment( + timestamp, + flops, + traceInterval, + cpuUsage, + cores + ) + ) } else { val oldFragment = flopsHistory.removeAt(flopsHistory.size - 1) flopsHistory.add( - FlopsHistoryFragment( - oldFragment.tick, + SimTraceWorkload.Fragment( + oldFragment.time, oldFragment.flops + flops, oldFragment.duration + traceInterval, cpuUsage, @@ -125,22 +131,27 @@ class BitbrainsTraceReader( val relevantPerformanceInterferenceModelItems = PerformanceInterferenceModel( - performanceInterferenceModel.items.filter { it.workloadNames.contains(vmId.toString()) }.toSortedSet() + performanceInterferenceModel.items.filter { it.workloadNames.contains(vmId.toString()) } + .toSortedSet() ) val vmWorkload = VmWorkload( - uuid, "VM Workload $vmId", UnnamedUser, - VmImage( + uuid, + "VM Workload $vmId", + UnnamedUser, + 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/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/gwf/GwfTraceReader.kt b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/gwf/GwfTraceReader.kt index 3a4e2e89..a20b4f29 100644 --- a/simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/gwf/GwfTraceReader.kt +++ b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/gwf/GwfTraceReader.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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,37 @@ * SOFTWARE. */ -package com.atlarge.opendc.format.trace.gwf +package org.opendc.format.trace.gwf -import com.atlarge.opendc.compute.core.image.FlopsApplicationImage -import com.atlarge.opendc.core.User -import com.atlarge.opendc.format.trace.TraceEntry -import com.atlarge.opendc.format.trace.TraceReader -import com.atlarge.opendc.workflows.workload.Job -import com.atlarge.opendc.workflows.workload.Task -import com.atlarge.opendc.workflows.workload.WORKFLOW_TASK_DEADLINE +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 import java.io.BufferedReader import java.io.File import java.io.InputStream -import java.util.UUID +import java.util.* +import kotlin.collections.HashSet +import kotlin.collections.Iterator +import kotlin.collections.List +import kotlin.collections.MutableSet +import kotlin.collections.component1 +import kotlin.collections.component2 +import kotlin.collections.emptyMap +import kotlin.collections.filter +import kotlin.collections.forEach +import kotlin.collections.getOrPut +import kotlin.collections.map +import kotlin.collections.mapIndexed +import kotlin.collections.mapOf +import kotlin.collections.mutableMapOf +import kotlin.collections.set +import kotlin.collections.sortedBy +import kotlin.collections.toMap import kotlin.math.max import kotlin.math.min @@ -48,7 +64,7 @@ import kotlin.math.min * * @param reader The buffered reader to read the trace with. */ -class GwfTraceReader(reader: BufferedReader) : TraceReader<Job> { +public class GwfTraceReader(reader: BufferedReader) : TraceReader<Job> { /** * The internal iterator to use for this reader. */ @@ -59,14 +75,14 @@ class GwfTraceReader(reader: BufferedReader) : TraceReader<Job> { * * @param file The file to read from. */ - constructor(file: File) : this(file.bufferedReader()) + public constructor(file: File) : this(file.bufferedReader()) /** * Create a [GwfTraceReader] instance from the specified [InputStream]. * * @param input The input stream to read from. */ - constructor(input: InputStream) : this(input.bufferedReader()) + public constructor(input: InputStream) : this(input.bufferedReader()) /** * Initialize the reader. @@ -120,8 +136,9 @@ class GwfTraceReader(reader: BufferedReader) : TraceReader<Job> { } val workflow = entry.workload val task = Task( - UUID(0L, taskId), "<unnamed>", - FlopsApplicationImage(UUID.randomUUID(), "<unnamed>", emptyMap(), flops, cores), + UUID(0L, taskId), + "<unnamed>", + SimWorkloadImage(UUID.randomUUID(), "<unnamed>", emptyMap(), SimFlopsWorkload(flops, cores)), HashSet(), mapOf(WORKFLOW_TASK_DEADLINE to runtime) ) @@ -136,9 +153,11 @@ class GwfTraceReader(reader: BufferedReader) : TraceReader<Job> { // Fix dependencies and dependents for all tasks taskDependencies.forEach { (task, dependencies) -> - (task.dependencies as MutableSet<Task>).addAll(dependencies.map { taskId -> - tasks[taskId] ?: throw IllegalArgumentException("Dependency task with id $taskId not found") - }) + (task.dependencies as MutableSet<Task>).addAll( + dependencies.map { taskId -> + tasks[taskId] ?: throw IllegalArgumentException("Dependency task with id $taskId not found") + } + ) } // Create the entry iterator diff --git a/simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/sc20/PerformanceInterferenceEntry.kt b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/sc20/PerformanceInterferenceEntry.kt index ade47e1b..0da1f7c2 100644 --- a/simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/sc20/PerformanceInterferenceEntry.kt +++ b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/sc20/PerformanceInterferenceEntry.kt @@ -1,4 +1,4 @@ -package com.atlarge.opendc.format.trace.sc20 +package org.opendc.format.trace.sc20 internal data class PerformanceInterferenceEntry( val vms: List<String>, diff --git a/simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/sc20/Sc20PerformanceInterferenceReader.kt b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/sc20/Sc20PerformanceInterferenceReader.kt index 0e8e1fd2..4267737d 100644 --- a/simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/sc20/Sc20PerformanceInterferenceReader.kt +++ b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/sc20/Sc20PerformanceInterferenceReader.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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,16 +20,15 @@ * SOFTWARE. */ -package com.atlarge.opendc.format.trace.sc20 +package org.opendc.format.trace.sc20 -import com.atlarge.opendc.compute.core.workload.PerformanceInterferenceModel -import com.atlarge.opendc.compute.core.workload.PerformanceInterferenceModelItem -import com.atlarge.opendc.format.trace.PerformanceInterferenceModelReader import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.fasterxml.jackson.module.kotlin.readValue +import org.opendc.format.trace.PerformanceInterferenceModelReader +import org.opendc.simulator.compute.interference.PerformanceInterferenceModel import java.io.InputStream -import java.util.TreeSet +import java.util.* import kotlin.random.Random /** @@ -40,18 +37,18 @@ import kotlin.random.Random * @param input The input stream to read from. * @param mapper The Jackson object mapper to use. */ -class Sc20PerformanceInterferenceReader(input: InputStream, mapper: ObjectMapper = jacksonObjectMapper()) : +public class Sc20PerformanceInterferenceReader(input: InputStream, mapper: ObjectMapper = jacksonObjectMapper()) : PerformanceInterferenceModelReader { /** * 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/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/sc20/Sc20TraceReader.kt b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/sc20/Sc20TraceReader.kt index 8e34505a..66efbcd0 100644 --- a/simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/sc20/Sc20TraceReader.kt +++ b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/sc20/Sc20TraceReader.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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,20 +20,20 @@ * SOFTWARE. */ -package com.atlarge.opendc.format.trace.sc20 +package org.opendc.format.trace.sc20 -import com.atlarge.opendc.compute.core.image.FlopsHistoryFragment -import com.atlarge.opendc.compute.core.image.VmImage -import com.atlarge.opendc.compute.core.workload.IMAGE_PERF_INTERFERENCE_MODEL -import com.atlarge.opendc.compute.core.workload.PerformanceInterferenceModel -import com.atlarge.opendc.compute.core.workload.VmWorkload -import com.atlarge.opendc.core.User -import com.atlarge.opendc.format.trace.TraceEntry -import com.atlarge.opendc.format.trace.TraceReader +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 -import java.util.UUID +import java.util.* import kotlin.math.max import kotlin.math.min import kotlin.random.Random @@ -46,7 +44,7 @@ import kotlin.random.Random * @param traceDirectory The directory of the traces. * @param performanceInterferenceModel The performance model covering the workload in the VM trace. */ -class Sc20TraceReader( +public class Sc20TraceReader( traceDirectory: File, performanceInterferenceModel: PerformanceInterferenceModel, selectedVms: List<String>, @@ -66,7 +64,6 @@ class Sc20TraceReader( val timestampCol = 0 val cpuUsageCol = 1 val coreCol = 12 - val vmIdCol = 19 val provisionedMemoryCol = 20 val traceInterval = 5 * 60 * 1000L @@ -111,7 +108,7 @@ class Sc20TraceReader( } val flopsFragments = sequence { - var last: FlopsHistoryFragment? = null + var last: SimTraceWorkload.Fragment? = null BufferedReader(FileReader(vmFile)).use { reader -> reader.lineSequence() @@ -132,8 +129,8 @@ 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, @@ -141,7 +138,7 @@ class Sc20TraceReader( ) } else { val fragment = - FlopsHistoryFragment(timestamp, flops, traceInterval, cpuUsage, cores) + SimTraceWorkload.Fragment(timestamp, flops, traceInterval, cpuUsage, cores) if (last != null) { yield(last!!) } @@ -164,14 +161,18 @@ class Sc20TraceReader( Random(random.nextInt()) ) val vmWorkload = VmWorkload( - uuid, "VM Workload $vmId", UnnamedUser, - VmImage( + uuid, + "VM Workload $vmId", + UnnamedUser, + 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/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/sc20/Sc20VmPlacementReader.kt b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/sc20/Sc20VmPlacementReader.kt index 5295ae03..61bdea60 100644 --- a/simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/sc20/Sc20VmPlacementReader.kt +++ b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/sc20/Sc20VmPlacementReader.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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,12 +20,12 @@ * SOFTWARE. */ -package com.atlarge.opendc.format.trace.sc20 +package org.opendc.format.trace.sc20 -import com.atlarge.opendc.format.trace.VmPlacementReader import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.fasterxml.jackson.module.kotlin.readValue +import org.opendc.format.trace.VmPlacementReader import java.io.InputStream /** @@ -36,7 +34,7 @@ import java.io.InputStream * @param input The input stream to read from. * @param mapper The Jackson object mapper to use. */ -class Sc20VmPlacementReader(input: InputStream, mapper: ObjectMapper = jacksonObjectMapper()) : +public class Sc20VmPlacementReader(input: InputStream, mapper: ObjectMapper = jacksonObjectMapper()) : VmPlacementReader { /** * The environment that was read from the file. diff --git a/simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/swf/SwfTraceReader.kt b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/swf/SwfTraceReader.kt index 2f6ce238..52d41c44 100644 --- a/simulator/opendc/opendc-format/src/main/kotlin/com/atlarge/opendc/format/trace/swf/SwfTraceReader.kt +++ b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/swf/SwfTraceReader.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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,18 +20,18 @@ * SOFTWARE. */ -package com.atlarge.opendc.format.trace.swf +package org.opendc.format.trace.swf -import com.atlarge.opendc.compute.core.image.FlopsHistoryFragment -import com.atlarge.opendc.compute.core.image.VmImage -import com.atlarge.opendc.compute.core.workload.VmWorkload -import com.atlarge.opendc.core.User -import com.atlarge.opendc.format.trace.TraceEntry -import com.atlarge.opendc.format.trace.TraceReader +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 -import java.util.UUID +import java.util.* /** * A [TraceReader] for reading SWF traces into VM-modeled workloads. @@ -42,7 +40,7 @@ import java.util.UUID * * @param file The trace file. */ -class SwfTraceReader( +public class SwfTraceReader( file: File, maxNumCores: Int = -1 ) : TraceReader<VmWorkload> { @@ -66,17 +64,17 @@ 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() @@ -105,7 +103,7 @@ class SwfTraceReader( memory /= 1000 // convert KB to MB } - val flopsHistory = mutableListOf<FlopsHistoryFragment>() + val flopsHistory = mutableListOf<SimTraceWorkload.Fragment>() // Insert waiting time slices @@ -114,8 +112,12 @@ class SwfTraceReader( if (waitTime >= sliceDuration) { for (tick in submitTime until (submitTime + waitTime - sliceDuration) step sliceDuration) { flopsHistory.add( - FlopsHistoryFragment( - tick * 1000L, 0L, sliceDuration * 1000L, 0.0, cores + SimTraceWorkload.Fragment( + tick * 1000L, + 0L, + sliceDuration * 1000L, + 0.0, + cores ) ) slicedWaitTime += sliceDuration @@ -129,19 +131,25 @@ class SwfTraceReader( flopsPartialSlice = flopsPerSecond * runtimePartialSliceRemainder flopsFullSlice = flopsPerSecond * runTime - flopsPartialSlice - for (tick in (submitTime + slicedWaitTime) - until (submitTime + slicedWaitTime + runTime - sliceDuration) - step sliceDuration) { + for ( + tick in (submitTime + slicedWaitTime) + until (submitTime + slicedWaitTime + runTime - sliceDuration) + step sliceDuration + ) { flopsHistory.add( - FlopsHistoryFragment( - tick * 1000L, flopsFullSlice / sliceDuration, sliceDuration * 1000L, 1.0, cores + SimTraceWorkload.Fragment( + tick * 1000L, + flopsFullSlice / sliceDuration, + sliceDuration * 1000L, + 1.0, + cores ) ) } if (runtimePartialSliceRemainder > 0) { flopsHistory.add( - FlopsHistoryFragment( + SimTraceWorkload.Fragment( submitTime + (slicedWaitTime + runTime - runtimePartialSliceRemainder), flopsPartialSlice, sliceDuration, @@ -153,14 +161,17 @@ class SwfTraceReader( val uuid = UUID(0L, jobNumber) val vmWorkload = VmWorkload( - uuid, "SWF Workload $jobNumber", UnnamedUser, - VmImage( + uuid, + "SWF Workload $jobNumber", + UnnamedUser, + 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 new file mode 100644 index 00000000..b2931468 --- /dev/null +++ b/simulator/opendc-format/src/main/kotlin/org/opendc/format/trace/wtf/WtfTraceReader.kt @@ -0,0 +1,128 @@ +/* + * 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.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.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 +import java.util.UUID +import kotlin.math.min + +/** + * A [TraceReader] for the Workflow Trace Format (WTF). See the Workflow Trace Archive + * (https://wta.atlarge-research.com/) for more information about the format. + * + * @param path The path to the trace. + */ +public class WtfTraceReader(path: String) : TraceReader<Job> { + /** + * The internal iterator to use for this reader. + */ + private val iterator: Iterator<TraceEntry<Job>> + + /** + * Initialize the reader. + */ + init { + val entries = mutableMapOf<Long, TraceEntryImpl>() + val tasks = mutableMapOf<Long, Task>() + val taskDependencies = mutableMapOf<Task, List<Long>>() + + val reader = AvroParquetReader.builder<GenericRecord>(Path(path, "tasks/schema-1.0")).build() + + while (true) { + val nextRecord = reader.read() ?: break + + val workflowId = nextRecord.get("workflow_id") as Long + val taskId = nextRecord.get("id") as Long + val submitTime = nextRecord.get("ts_submit") as Long + val runtime = nextRecord.get("runtime") as Long + val cores = (nextRecord.get("resource_amount_requested") as Double).toInt() + @Suppress("UNCHECKED_CAST") + val dependencies = (nextRecord.get("parents") as ArrayList<GenericRecord>).map { + it.get("item") as Long + } + + val flops: Long = 4100 * (runtime / 1000) * cores + + val entry = entries.getOrPut(workflowId) { + TraceEntryImpl(submitTime, Job(UUID(0L, taskId), "<unnamed>", UnnamedUser, HashSet())) + } + val workflow = entry.workload + val task = Task( + UUID(0L, taskId), + "<unnamed>", + SimWorkloadImage(UUID.randomUUID(), "<unnamed>", emptyMap(), SimFlopsWorkload(flops, cores)), + HashSet(), + mapOf(WORKFLOW_TASK_DEADLINE to runtime) + ) + + entry.submissionTime = min(entry.submissionTime, submitTime) + (workflow.tasks as MutableSet<Task>).add(task) + tasks[taskId] = task + taskDependencies[task] = dependencies + } + + // Fix dependencies and dependents for all tasks + taskDependencies.forEach { (task, dependencies) -> + (task.dependencies as MutableSet<Task>).addAll( + dependencies.map { taskId -> + tasks[taskId] ?: throw IllegalArgumentException("Dependency task with id $taskId not found") + } + ) + } + + // Create the entry iterator + iterator = entries.values.sortedBy { it.submissionTime }.iterator() + } + + override fun hasNext(): Boolean = iterator.hasNext() + + override fun next(): TraceEntry<Job> = iterator.next() + + override fun close() {} + + /** + * An unnamed user. + */ + private object UnnamedUser : User { + override val name: String = "<unnamed>" + override val uid: UUID = UUID.randomUUID() + } + + /** + * An entry in the trace. + */ + private data class TraceEntryImpl( + override var submissionTime: Long, + override val workload: Job + ) : TraceEntry<Job> +} 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 new file mode 100644 index 00000000..8db2ab40 --- /dev/null +++ b/simulator/opendc-format/src/test/kotlin/org/opendc/format/trace/swf/SwfTraceReaderTest.kt @@ -0,0 +1,47 @@ +/* + * 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.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 { + @Test + internal fun testParseSwf() { + val reader = SwfTraceReader(File(SwfTraceReaderTest::class.java.getResource("/swf_trace.txt").toURI())) + var entry = reader.next() + assertEquals(0, entry.submissionTime) + // 1961 slices for waiting, 3 full and 1 partial running slices + 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 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-format/src/test/kotlin/org/opendc/format/trace/wtf/WtfTraceReaderTest.kt b/simulator/opendc-format/src/test/kotlin/org/opendc/format/trace/wtf/WtfTraceReaderTest.kt new file mode 100644 index 00000000..58d96657 --- /dev/null +++ b/simulator/opendc-format/src/test/kotlin/org/opendc/format/trace/wtf/WtfTraceReaderTest.kt @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020 AtLarge Research + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package org.opendc.format.trace.wtf + +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Test + +/** + * Test suite for the [WtfTraceReader] class. + */ +class WtfTraceReaderTest { + /** + * Smoke test for parsing WTF traces. + */ + @Test + fun testParseWtf() { + val reader = WtfTraceReader("src/test/resources/wtf-trace") + var entry = reader.next() + assertEquals(0, entry.submissionTime) + assertEquals(23, entry.workload.tasks.size) + + entry = reader.next() + assertEquals(333387, entry.submissionTime) + assertEquals(23, entry.workload.tasks.size) + } +} diff --git a/simulator/opendc/opendc-format/src/test/resources/swf_trace.txt b/simulator/opendc-format/src/test/resources/swf_trace.txt index c3ecf890..c3ecf890 100644 --- a/simulator/opendc/opendc-format/src/test/resources/swf_trace.txt +++ b/simulator/opendc-format/src/test/resources/swf_trace.txt diff --git a/simulator/opendc-format/src/test/resources/wtf-trace/tasks/schema-1.0/part.0.parquet b/simulator/opendc-format/src/test/resources/wtf-trace/tasks/schema-1.0/part.0.parquet Binary files differnew file mode 100644 index 00000000..d2044038 --- /dev/null +++ b/simulator/opendc-format/src/test/resources/wtf-trace/tasks/schema-1.0/part.0.parquet diff --git a/simulator/opendc/opendc-runner-web/build.gradle.kts b/simulator/opendc-runner-web/build.gradle.kts index 6f725de1..cf437843 100644 --- a/simulator/opendc/opendc-runner-web/build.gradle.kts +++ b/simulator/opendc-runner-web/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 @@ -31,14 +29,16 @@ plugins { } application { - mainClassName = "com.atlarge.opendc.runner.web.MainKt" + mainClassName = "org.opendc.runner.web.MainKt" } dependencies { - api(project(":opendc:opendc-core")) - implementation(project(":opendc:opendc-compute")) - implementation(project(":opendc:opendc-format")) - implementation(project(":opendc:opendc-experiments-sc20")) + api(project(":opendc-core")) + implementation(project(":opendc-compute:opendc-compute-simulator")) + implementation(project(":opendc-format")) + implementation(project(":opendc-experiments:opendc-experiments-sc20")) + 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") @@ -49,7 +49,6 @@ dependencies { exclude(group = "log4j") } - runtimeOnly(project(":odcsim:odcsim-engine-omega")) runtimeOnly("org.apache.logging.log4j:log4j-slf4j-impl:2.13.1") runtimeOnly("org.apache.logging.log4j:log4j-1.2-api:2.13.1") } diff --git a/simulator/opendc/opendc-runner-web/src/main/kotlin/com/atlarge/opendc/runner/web/Main.kt b/simulator/opendc-runner-web/src/main/kotlin/org/opendc/runner/web/Main.kt index 807c119e..26577ef2 100644 --- a/simulator/opendc/opendc-runner-web/src/main/kotlin/com/atlarge/opendc/runner/web/Main.kt +++ b/simulator/opendc-runner-web/src/main/kotlin/org/opendc/runner/web/Main.kt @@ -1,16 +1,27 @@ -package com.atlarge.opendc.runner.web - -import com.atlarge.odcsim.SimulationEngineProvider -import com.atlarge.opendc.compute.virt.service.allocation.* -import com.atlarge.opendc.experiments.sc20.experiment.attachMonitor -import com.atlarge.opendc.experiments.sc20.experiment.createFailureDomain -import com.atlarge.opendc.experiments.sc20.experiment.createProvisioner -import com.atlarge.opendc.experiments.sc20.experiment.model.Workload -import com.atlarge.opendc.experiments.sc20.experiment.monitor.ParquetExperimentMonitor -import com.atlarge.opendc.experiments.sc20.experiment.processTrace -import com.atlarge.opendc.experiments.sc20.trace.Sc20ParquetTraceReader -import com.atlarge.opendc.experiments.sc20.trace.Sc20RawParquetTraceReader -import com.atlarge.opendc.format.trace.sc20.Sc20PerformanceInterferenceReader +/* + * 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.runner.web + import com.github.ajalt.clikt.core.CliktCommand import com.github.ajalt.clikt.parameters.options.* import com.github.ajalt.clikt.parameters.types.file @@ -22,25 +33,32 @@ import com.mongodb.client.MongoClients import com.mongodb.client.MongoCollection import com.mongodb.client.MongoDatabase import com.mongodb.client.model.Filters -import java.io.File -import java.util.* -import kotlin.random.Random import kotlinx.coroutines.* import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.test.TestCoroutineScope import mu.KotlinLogging import org.bson.Document +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 +import org.opendc.experiments.sc20.experiment.model.Workload +import org.opendc.experiments.sc20.experiment.monitor.ParquetExperimentMonitor +import org.opendc.experiments.sc20.experiment.processTrace +import org.opendc.experiments.sc20.trace.Sc20ParquetTraceReader +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 kotlin.random.Random private val logger = KotlinLogging.logger {} /** - * The provider for the simulation engine to use. - */ -private val provider = ServiceLoader.load(SimulationEngineProvider::class.java).first() - -/** * Represents the CLI command for starting the OpenDC web runner. */ -class RunnerCli : CliktCommand(name = "runner") { +@OptIn(ExperimentalCoroutinesApi::class) +public class RunnerCli : CliktCommand(name = "runner") { /** * The name of the database to use. */ @@ -195,8 +213,8 @@ class RunnerCli : CliktCommand(name = "runner") { val workloadFraction = traceDocument.get("loadSamplingFraction", Number::class.java).toDouble() val seeder = Random(seed) - val system = provider("experiment-$id") - val root = system.newDomain("root") + val testScope = TestCoroutineScope() + val clock = DelayControllerClockAdapter(testScope) val chan = Channel<Unit>(Channel.CONFLATED) @@ -230,9 +248,10 @@ class RunnerCli : CliktCommand(name = "runner") { 4096 ) - root.launch { + testScope.launch { val (bareMetalProvisioner, scheduler) = createProvisioner( - root, + this, + clock, environment, allocationPolicy ) @@ -240,6 +259,8 @@ class RunnerCli : CliktCommand(name = "runner") { val failureDomain = if (operational.getBoolean("failuresEnabled")) { logger.debug("ENABLING failures") createFailureDomain( + testScope, + clock, seeder.nextInt(), operational.get("failureFrequency", Number::class.java)?.toDouble() ?: 24.0 * 7, bareMetalProvisioner, @@ -249,13 +270,14 @@ class RunnerCli : CliktCommand(name = "runner") { null } - attachMonitor(scheduler, monitor) + attachMonitor(this, clock, scheduler, monitor) processTrace( + this, + clock, trace, scheduler, chan, - monitor, - emptyMap() + monitor ) logger.debug("SUBMIT=${scheduler.submittedVms}") @@ -269,17 +291,16 @@ class RunnerCli : CliktCommand(name = "runner") { } try { - system.run() + testScope.advanceUntilIdle() } finally { - system.terminate() monitor.close() } } - val POLL_INTERVAL = 5000L // ms = 5 s - val HEARTBEAT_INTERVAL = 60000L // ms = 1 min + private val POLL_INTERVAL = 5000L // ms = 5 s + private val HEARTBEAT_INTERVAL = 60000L // ms = 1 min - override fun run() = runBlocking(Dispatchers.Default) { + override fun run(): Unit = runBlocking(Dispatchers.Default) { logger.info { "Starting OpenDC web runner" } logger.info { "Connecting to MongoDB instance" } val database = createDatabase() @@ -342,4 +363,4 @@ class RunnerCli : CliktCommand(name = "runner") { /** * Main entry point of the runner. */ -fun main(args: Array<String>) = RunnerCli().main(args) +public fun main(args: Array<String>): Unit = RunnerCli().main(args) diff --git a/simulator/opendc/opendc-runner-web/src/main/kotlin/com/atlarge/opendc/runner/web/ResultProcessor.kt b/simulator/opendc-runner-web/src/main/kotlin/org/opendc/runner/web/ResultProcessor.kt index 39092653..f9a3cd2b 100644 --- a/simulator/opendc/opendc-runner-web/src/main/kotlin/com/atlarge/opendc/runner/web/ResultProcessor.kt +++ b/simulator/opendc-runner-web/src/main/kotlin/org/opendc/runner/web/ResultProcessor.kt @@ -1,20 +1,42 @@ -package com.atlarge.opendc.runner.web +/* + * 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.runner.web -import java.io.File import org.apache.spark.sql.Column import org.apache.spark.sql.Dataset import org.apache.spark.sql.Row import org.apache.spark.sql.SparkSession import org.apache.spark.sql.functions.* +import java.io.File /** * A helper class for processing the experiment results using Apache Spark. */ -class ResultProcessor(private val master: String, private val outputPath: File) { +public class ResultProcessor(private val master: String, private val outputPath: File) { /** * Process the results of the scenario with the given [id]. */ - fun process(id: String): Result { + public fun process(id: String): Result { val spark = SparkSession.builder() .master(master) .appName("opendc-simulator-$id") @@ -48,22 +70,22 @@ class ResultProcessor(private val master: String, private val outputPath: File) } } - data class Result( - val totalRequestedBurst: List<Long>, - val totalGrantedBurst: List<Long>, - val totalOvercommittedBurst: List<Long>, - val totalInterferedBurst: List<Long>, - val meanCpuUsage: List<Double>, - val meanCpuDemand: List<Double>, - val meanNumDeployedImages: List<Double>, - val maxNumDeployedImages: List<Int>, - val totalPowerDraw: List<Long>, - val totalFailureSlices: List<Long>, - val totalFailureVmSlices: List<Long>, - val totalVmsSubmitted: List<Int>, - val totalVmsQueued: List<Int>, - val totalVmsFinished: List<Int>, - val totalVmsFailed: List<Int> + public data class Result( + public val totalRequestedBurst: List<Long>, + public val totalGrantedBurst: List<Long>, + public val totalOvercommittedBurst: List<Long>, + public val totalInterferedBurst: List<Long>, + public val meanCpuUsage: List<Double>, + public val meanCpuDemand: List<Double>, + public val meanNumDeployedImages: List<Double>, + public val maxNumDeployedImages: List<Int>, + public val totalPowerDraw: List<Long>, + public val totalFailureSlices: List<Long>, + public val totalFailureVmSlices: List<Long>, + public val totalVmsSubmitted: List<Int>, + public val totalVmsQueued: List<Int>, + public val totalVmsFinished: List<Int>, + public val totalVmsFailed: List<Int> ) /** @@ -169,19 +191,25 @@ class ResultProcessor(private val master: String, private val outputPath: File) } // Spark helper functions - operator fun Column.times(other: Column): Column = `$times`(other) - operator fun Column.div(other: Column): Column = `$div`(other) - operator fun Column.get(other: Column): Column = this.apply(other) + private operator fun Column.times(other: Column): Column = `$times`(other) + private operator fun Column.div(other: Column): Column = `$div`(other) + private operator fun Column.get(other: Column): Column = this.apply(other) - val sliceLength = 5 * 60 * 1000 - val states = map( - lit("ERROR"), lit(1), - lit("ACTIVE"), lit(0), - lit("SHUTOFF"), lit(0) + private val sliceLength = 5 * 60 * 1000 + private val states = map( + lit("ERROR"), + lit(1), + lit("ACTIVE"), + lit(0), + lit("SHUTOFF"), + lit(0) ) - val oppositeStates = map( - lit("ERROR"), lit(0), - lit("ACTIVE"), lit(1), - lit("SHUTOFF"), lit(1) + private val oppositeStates = map( + lit("ERROR"), + lit(0), + lit("ACTIVE"), + lit(1), + lit("SHUTOFF"), + lit(1) ) } diff --git a/simulator/opendc/opendc-runner-web/src/main/kotlin/com/atlarge/opendc/runner/web/ScenarioManager.kt b/simulator/opendc-runner-web/src/main/kotlin/org/opendc/runner/web/ScenarioManager.kt index 40ffd282..504fccdc 100644 --- a/simulator/opendc/opendc-runner-web/src/main/kotlin/com/atlarge/opendc/runner/web/ScenarioManager.kt +++ b/simulator/opendc-runner-web/src/main/kotlin/org/opendc/runner/web/ScenarioManager.kt @@ -1,19 +1,41 @@ -package com.atlarge.opendc.runner.web +/* + * 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.runner.web import com.mongodb.client.MongoCollection import com.mongodb.client.model.Filters import com.mongodb.client.model.Updates -import java.time.Instant import org.bson.Document +import java.time.Instant /** * Manages the queue of scenarios that need to be processed. */ -class ScenarioManager(private val collection: MongoCollection<Document>) { +public class ScenarioManager(private val collection: MongoCollection<Document>) { /** * Find the next scenario that the simulator needs to process. */ - fun findNext(): Document? { + public fun findNext(): Document? { return collection .find(Filters.eq("simulation.state", "QUEUED")) .first() @@ -22,7 +44,7 @@ class ScenarioManager(private val collection: MongoCollection<Document>) { /** * Claim the scenario in the database with the specified id. */ - fun claim(id: String): Boolean { + public fun claim(id: String): Boolean { val res = collection.findOneAndUpdate( Filters.and( Filters.eq("_id", id), @@ -39,7 +61,7 @@ class ScenarioManager(private val collection: MongoCollection<Document>) { /** * Update the heartbeat of the specified scenario. */ - fun heartbeat(id: String) { + public fun heartbeat(id: String) { collection.findOneAndUpdate( Filters.and( Filters.eq("_id", id), @@ -52,7 +74,7 @@ class ScenarioManager(private val collection: MongoCollection<Document>) { /** * Mark the scenario as failed. */ - fun fail(id: String) { + public fun fail(id: String) { collection.findOneAndUpdate( Filters.eq("_id", id), Updates.combine( @@ -65,7 +87,7 @@ class ScenarioManager(private val collection: MongoCollection<Document>) { /** * Persist the specified results. */ - fun finish(id: String, result: ResultProcessor.Result) { + public fun finish(id: String, result: ResultProcessor.Result) { collection.findOneAndUpdate( Filters.eq("_id", id), Updates.combine( diff --git a/simulator/opendc/opendc-runner-web/src/main/kotlin/com/atlarge/opendc/runner/web/TopologyParser.kt b/simulator/opendc-runner-web/src/main/kotlin/org/opendc/runner/web/TopologyParser.kt index 499585ec..5e483271 100644 --- a/simulator/opendc/opendc-runner-web/src/main/kotlin/com/atlarge/opendc/runner/web/TopologyParser.kt +++ b/simulator/opendc-runner-web/src/main/kotlin/org/opendc/runner/web/TopologyParser.kt @@ -1,42 +1,65 @@ -package com.atlarge.opendc.runner.web +/* + * 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.runner.web -import com.atlarge.odcsim.Domain -import com.atlarge.opendc.compute.core.MemoryUnit -import com.atlarge.opendc.compute.core.ProcessingNode -import com.atlarge.opendc.compute.core.ProcessingUnit -import com.atlarge.opendc.compute.metal.NODE_CLUSTER -import com.atlarge.opendc.compute.metal.driver.SimpleBareMetalDriver -import com.atlarge.opendc.compute.metal.power.LinearLoadPowerModel -import com.atlarge.opendc.compute.metal.service.ProvisioningService -import com.atlarge.opendc.compute.metal.service.SimpleProvisioningService -import com.atlarge.opendc.core.Environment -import com.atlarge.opendc.core.Platform -import com.atlarge.opendc.core.Zone -import com.atlarge.opendc.core.services.ServiceRegistry -import com.atlarge.opendc.format.environment.EnvironmentReader import com.mongodb.client.AggregateIterable import com.mongodb.client.MongoCollection import com.mongodb.client.model.Aggregates import com.mongodb.client.model.Field import com.mongodb.client.model.Filters import com.mongodb.client.model.Projections -import java.util.* +import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import org.bson.Document +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.* /** * A helper class that converts the MongoDB topology into an OpenDC environment. */ -class TopologyParser(private val collection: MongoCollection<Document>, private val id: String) : EnvironmentReader { +public class TopologyParser(private val collection: MongoCollection<Document>, private val id: String) : EnvironmentReader { /** * Parse the topology with the specified [id]. */ - override suspend fun construct(dom: Domain): Environment { - val nodes = mutableListOf<SimpleBareMetalDriver>() + override suspend fun construct(coroutineScope: CoroutineScope, clock: Clock): Environment { + 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") @@ -58,13 +81,13 @@ class TopologyParser(private val collection: MongoCollection<Document>, private ) } nodes.add( - SimpleBareMetalDriver( - dom.newDomain(machineId), + 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 @@ -73,8 +96,8 @@ class TopologyParser(private val collection: MongoCollection<Document>, private ) } - val provisioningService = SimpleProvisioningService(dom.newDomain("provisioner")) - dom.launch { + val provisioningService = SimpleProvisioningService() + coroutineScope.launch { for (node in nodes) { provisioningService.create(node) } @@ -83,7 +106,9 @@ class TopologyParser(private val collection: MongoCollection<Document>, private val serviceRegistry = ServiceRegistry().put(ProvisioningService, provisioningService) val platform = Platform( - UUID.randomUUID(), "opendc-platform", listOf( + UUID.randomUUID(), + "opendc-platform", + listOf( Zone(UUID.randomUUID(), "zone", serviceRegistry) ) ) diff --git a/simulator/opendc/opendc-runner-web/src/main/resources/log4j2.xml b/simulator/opendc-runner-web/src/main/resources/log4j2.xml index 1d873554..16cedf34 100644 --- a/simulator/opendc/opendc-runner-web/src/main/resources/log4j2.xml +++ b/simulator/opendc-runner-web/src/main/resources/log4j2.xml @@ -26,17 +26,14 @@ <Configuration status="WARN"> <Appenders> <Console name="Console" target="SYSTEM_OUT"> - <PatternLayout pattern="%d{HH:mm:ss.SSS} [%highlight{%-5level}] %logger{36} - %msg%n" disableAnsi="false" /> + <PatternLayout pattern="%d{HH:mm:ss.SSS} [%highlight{%-5level}] %logger{36} - %msg%n" disableAnsi="false"/> </Console> </Appenders> <Loggers> - <Logger name="com.atlarge.odcsim" level="info" additivity="false"> + <Logger name="org.opendc" level="warn" additivity="false"> <AppenderRef ref="Console"/> </Logger> - <Logger name="com.atlarge.opendc" level="warn" additivity="false"> - <AppenderRef ref="Console"/> - </Logger> - <Logger name="com.atlarge.opendc.runner" level="info" additivity="false"> + <Logger name="org.opendc.runner" level="info" additivity="false"> <AppenderRef ref="Console"/> </Logger> <Logger name="org.apache.hadoop" level="warn" additivity="false"> diff --git a/simulator/opendc-simulator/build.gradle.kts b/simulator/opendc-simulator/build.gradle.kts new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/simulator/opendc-simulator/build.gradle.kts diff --git a/simulator/odcsim/odcsim-api/build.gradle.kts b/simulator/opendc-simulator/opendc-simulator-compute/build.gradle.kts index c8c6c90c..cd7e5706 100644 --- a/simulator/odcsim/odcsim-api/build.gradle.kts +++ b/simulator/opendc-simulator/opendc-simulator-compute/build.gradle.kts @@ -1,7 +1,5 @@ /* - * MIT License - * - * 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 @@ -22,17 +20,14 @@ * SOFTWARE. */ -description = "Framework for discrete event simulation in Kotlin" +description = "Library for simulation of cloud computing components" -/* Build configuration */ plugins { `kotlin-library-convention` } dependencies { - implementation(kotlin("stdlib")) - api("org.slf4j:slf4j-api:${Library.SLF4J}") - api("org.jetbrains.kotlinx:kotlinx-coroutines-core:${Library.KOTLINX_COROUTINES}") + api(project(":opendc-simulator:opendc-simulator-core")) 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-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/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/execution/ServerContext.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimExecutionContext.kt index f770fa49..5801fcd5 100644 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/execution/ServerContext.kt +++ b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimExecutionContext.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,33 +20,27 @@ * SOFTWARE. */ -package com.atlarge.opendc.compute.core.execution +package org.opendc.simulator.compute -import com.atlarge.opendc.compute.core.ProcessingUnit -import com.atlarge.opendc.compute.core.Server -import com.atlarge.opendc.compute.core.image.Image -import com.atlarge.opendc.core.services.ServiceKey import kotlinx.coroutines.selects.SelectClause0 import kotlinx.coroutines.selects.select +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 { - /** - * The server on which the image runs. - */ - public val server: Server - +public interface SimExecutionContext { /** - * A list of processing units available to use. + * The virtual clock tracking simulation time. */ - public val cpus: List<ProcessingUnit> + public val clock: Clock /** - * Publish the specified [service] at the given [ServiceKey]. + * The machine model of the machine that is running the image. */ - 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 @@ -61,8 +53,8 @@ public interface ServerContext { * @param slice The representation of work to run on the processors. * @param triggerMode The trigger condition to resume execution. */ - public suspend fun run(slice: Slice, triggerMode: TriggerMode = TriggerMode.FIRST) = - select<Unit> { onRun(slice, triggerMode).invoke {} } + public suspend fun run(slice: Slice, triggerMode: TriggerMode = TriggerMode.FIRST): Unit = + select { onRun(slice, triggerMode).invoke {} } /** * Ask the processors cores to run the specified [batch] of work slices and suspend execution until the trigger @@ -84,7 +76,7 @@ public interface ServerContext { batch: Sequence<Slice>, triggerMode: TriggerMode = TriggerMode.FIRST, merge: (Slice, Slice) -> Slice = { _, r -> r } - ) = 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 @@ -133,7 +125,7 @@ public interface ServerContext { * @param limit The maximum usage in terms of MHz that the processing core may use while running the burst. * @param deadline The instant at which this slice needs to be fulfilled. */ - public class Slice(val burst: LongArray, val limit: DoubleArray, val deadline: Long) { + public class Slice(public val burst: LongArray, public val limit: DoubleArray, public val deadline: Long) { init { require(burst.size == limit.size) { "Incompatible array dimensions" } } diff --git a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/driver/SimpleVirtDriver.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimHypervisor.kt index 192db413..6087227b 100644 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/driver/SimpleVirtDriver.kt +++ b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimHypervisor.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,174 +20,100 @@ * SOFTWARE. */ -package com.atlarge.opendc.compute.virt.driver - -import com.atlarge.odcsim.flow.EventFlow -import com.atlarge.odcsim.simulationContext -import com.atlarge.opendc.compute.core.Flavor -import com.atlarge.opendc.compute.core.ProcessingUnit -import com.atlarge.opendc.compute.core.Server -import com.atlarge.opendc.compute.core.ServerEvent -import com.atlarge.opendc.compute.core.ServerState -import com.atlarge.opendc.compute.core.execution.ServerContext -import com.atlarge.opendc.compute.core.execution.ServerManagementContext -import com.atlarge.opendc.compute.core.execution.ShutdownException -import com.atlarge.opendc.compute.core.image.Image -import com.atlarge.opendc.compute.core.workload.IMAGE_PERF_INTERFERENCE_MODEL -import com.atlarge.opendc.compute.core.workload.PerformanceInterferenceModel -import com.atlarge.opendc.compute.virt.HypervisorEvent -import com.atlarge.opendc.core.services.ServiceKey -import com.atlarge.opendc.core.services.ServiceRegistry -import java.util.UUID -import kotlin.math.ceil -import kotlin.math.max -import kotlin.math.min -import kotlinx.coroutines.CancellationException -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.DisposableHandle -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.FlowPreview -import kotlinx.coroutines.InternalCoroutinesApi -import kotlinx.coroutines.Job +package org.opendc.simulator.compute + +import kotlinx.coroutines.* import kotlinx.coroutines.channels.Channel -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.intrinsics.startCoroutineCancellable -import kotlinx.coroutines.launch import kotlinx.coroutines.selects.SelectClause0 import kotlinx.coroutines.selects.SelectInstance import kotlinx.coroutines.selects.select +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 kotlin.math.ceil +import kotlin.math.max +import kotlin.math.min /** - * 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) -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. */ - 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 { - scheduler() - } catch (e: Exception) { - if (e !is CancellationException) { - simulationContext.log.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() - } - 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) + override fun toString(): String = "SimVirtualMachine" } } /** - * 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. - */ - private var stopped: Boolean = false - - /** - * The channel for scheduling new CPU requests. - */ - private val schedulingQueue = Channel<SchedulerCommand>(Channel.UNLIMITED) - - /** - * The scheduling process of the hypervisor. + * Run the scheduling process of the hypervisor. */ - private suspend fun scheduler() { - val clock = simulationContext.clock - val maxUsage = hostContext.cpus.sumByDouble { it.frequency } - val pCPUs = hostContext.cpus.indices.sortedBy { hostContext.cpus[it].frequency } + 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 } - 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) { @@ -201,7 +125,8 @@ class SimpleVirtDriver( vms -= command.vm vcpus.removeAll(command.vm.vcpus) } - is SchedulerCommand.Interrupt -> {} + is SchedulerCommand.Interrupt -> { + } } } @@ -223,7 +148,6 @@ 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 @@ -269,7 +193,7 @@ 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() @@ -284,7 +208,8 @@ 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).invoke { false } + ctx.onRun(SimExecutionContext.Slice(burst, usage, deadline), SimExecutionContext.TriggerMode.DEADLINE) + .invoke { false } } val end = clock.millis() @@ -295,7 +220,8 @@ class SimpleVirtDriver( } // The total requested burst that the VMs wanted to run in the time-frame that we ran. - val totalRequestedSubBurst = vcpus.map { ceil((duration * 1000) / (it.vm.deadline - start) * it.burst).toLong() }.sum() + val totalRequestedSubBurst = + vcpus.map { ceil((duration * 1000) / (it.vm.deadline - start) * it.burst).toLong() }.sum() val totalRemainder = burst.sum() val totalGrantedBurst = totalAllocatedBurst - totalRemainder @@ -309,9 +235,7 @@ 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) { @@ -329,7 +253,7 @@ 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 @@ -345,23 +269,60 @@ 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. @@ -370,10 +331,11 @@ 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 = {} ) { /** @@ -384,12 +346,12 @@ 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. @@ -403,19 +365,24 @@ 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() } } @@ -423,9 +390,9 @@ 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() } /** @@ -444,7 +411,7 @@ class SimpleVirtDriver( this.activeSlice = slice // Update the vCPU cache - vcpus.forEach { it.refresh() } + refresh() false } else { @@ -453,6 +420,14 @@ class SimpleVirtDriver( true } } + + /** + * Refresh the vCPU cache. + */ + fun refresh() { + vcpus.forEach { it.refresh() } + usage.value = vcpus.sumByDouble { it.burst / it.limit } / vcpus.size + } } /** @@ -463,7 +438,7 @@ 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> { @@ -506,119 +481,54 @@ 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) - } - } + private inner class VmExecutionContext(val session: VmSession) : + SimExecutionContext, DisposableHandle { + override val machine: SimMachineModel + get() = session.model - 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) - - 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() - } + override val clock: Clock + 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-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/interference/PerformanceInterferenceModel.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/interference/PerformanceInterferenceModel.kt new file mode 100644 index 00000000..4c409887 --- /dev/null +++ b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/interference/PerformanceInterferenceModel.kt @@ -0,0 +1,134 @@ +/* + * 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.interference + +import java.util.* +import kotlin.random.Random + +/** + * Meta-data key for the [PerformanceInterferenceModel] of an image. + */ +public const val IMAGE_PERF_INTERFERENCE_MODEL: String = "image:performance-interference" + +/** + * Performance Interference Model describing the variability incurred by different sets of workloads if colocated. + * + * @param items The [PerformanceInterferenceModel.Item]s that make up this model. + */ +public class PerformanceInterferenceModel( + public val items: SortedSet<Item>, + private val random: Random = Random(0) +) { + private var intersectingItems: List<Item> = emptyList() + private val colocatedWorkloads = TreeMap<String, Int>() + + /** + * Indicate that a VM has started. + */ + public fun onStart(name: String) { + colocatedWorkloads.merge(name, 1, Int::plus) + intersectingItems = items.filter { item -> doesMatch(item) } + } + + /** + * 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) } + } + + /** + * Compute the performance interference based on the current server load. + */ + public fun apply(currentServerLoad: Double): Double { + if (intersectingItems.isEmpty()) { + return 1.0 + } + val score = intersectingItems + .firstOrNull { it.minServerLoad <= currentServerLoad } + + // Apply performance penalty to (on average) only one of the VMs + return if (score != null && random.nextInt(score.workloadNames.size) == 0) { + score.performanceScore + } else { + 1.0 + } + } + + 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 + } + + /** + * 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 + } + + override fun hashCode(): Int = workloadNames.hashCode() + + override fun compareTo(other: Item): Int { + var cmp = performanceScore.compareTo(other.performanceScore) + if (cmp != 0) { + return cmp + } + + cmp = minServerLoad.compareTo(other.minServerLoad) + if (cmp != 0) { + return cmp + } + + return hashCode().compareTo(other.hashCode()) + } + } +} diff --git a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/MemoryUnit.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/MemoryUnit.kt index ce57fc72..bcbde5b1 100644 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/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 com.atlarge.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/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/ProcessingNode.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/ProcessingNode.kt index 91f5dde9..58ed816c 100644 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/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 com.atlarge.opendc.compute.core +package org.opendc.simulator.compute.model /** * A processing node/package/socket containing possibly several CPU cores. @@ -32,9 +30,9 @@ package com.atlarge.opendc.compute.core * @property arch The micro-architecture of the processor node. * @property coreCount The number of logical CPUs in the processor node. */ -data class ProcessingNode( - val vendor: String, - val arch: String, - val modelName: String, - val coreCount: Int +public data class ProcessingNode( + public val vendor: String, + public val arch: String, + public val modelName: String, + public val coreCount: Int ) diff --git a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/ProcessingUnit.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/ProcessingUnit.kt index ba148ee0..415e95e6 100644 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/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 com.atlarge.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/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/image/FlopsApplicationImage.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimFlopsWorkload.kt index d65e7e94..918a78bd 100644 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/image/FlopsApplicationImage.kt +++ b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimFlopsWorkload.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,32 +20,24 @@ * SOFTWARE. */ -package com.atlarge.opendc.compute.core.image +package org.opendc.simulator.compute.workload -import com.atlarge.opendc.compute.core.execution.ServerContext -import com.atlarge.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. */ -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" } @@ -57,11 +47,11 @@ 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/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/SimulationContext.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkload.kt index c51d1d8b..7b1ddf32 100644 --- a/simulator/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/SimulationContext.kt +++ b/simulator/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkload.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2018 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,42 +20,34 @@ * SOFTWARE. */ -package com.atlarge.odcsim +package org.opendc.simulator.compute.workload -import java.time.Clock -import kotlin.coroutines.CoroutineContext -import kotlin.coroutines.coroutineContext -import org.slf4j.Logger +import org.opendc.simulator.compute.SimExecutionContext +import kotlin.math.min /** - * Represents the execution context of a simulation domain. + * A [SimWorkload] that replays a workload trace consisting of multiple fragments, each indicating the resource + * consumption for some period of time. */ -public interface SimulationContext : CoroutineContext.Element { - /** - * Key for [SimulationContext] instance in the coroutine context. - */ - companion object Key : CoroutineContext.Key<SimulationContext> +public class SimTraceWorkload(public val trace: Sequence<Fragment>) : SimWorkload { + override suspend fun run(ctx: SimExecutionContext) { + var offset = ctx.clock.millis() - /** - * The reference to the current simulation domain. - */ - public val domain: Domain + 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 + SimExecutionContext.Slice(burst, usage, offset) + } - /** - * The clock tracking the simulation time. - */ - public val clock: Clock + ctx.run(batch) + } + + override fun toString(): String = "SimTraceWorkload" /** - * A logger instance tied to the logical process. + * A fragment of the workload. */ - public val log: Logger + public data class Fragment(val time: Long, val flops: Long, val duration: Long, val usage: Double, val cores: Int) } - -/** - * The simulation context of the current coroutine. - */ -@Suppress("WRONG_MODIFIER_TARGET") -public suspend inline val simulationContext: SimulationContext - @Suppress("ILLEGAL_SUSPEND_PROPERTY_ACCESS") - get() = coroutineContext[SimulationContext] ?: throw IllegalStateException("No simulation context available") 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/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/core/image/FlopsApplicationImageTest.kt b/simulator/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimFlopsWorkloadTest.kt index 1c7b751c..51bed76c 100644 --- a/simulator/opendc/opendc-compute/src/test/kotlin/com/atlarge/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 com.atlarge.opendc.compute.core.image +package org.opendc.simulator.compute.workload -import java.util.UUID -import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows /** - * 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/opendc-simulator-core/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 new file mode 100644 index 00000000..84c18e87 --- /dev/null +++ b/simulator/opendc-simulator/opendc-simulator-core/src/main/kotlin/org/opendc/simulator/utils/DelayControllerClockAdapter.kt @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2020 AtLarge Research + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package org.opendc.simulator.utils + +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.test.DelayController +import java.time.Clock +import java.time.Instant +import java.time.ZoneId + +/** + * A virtual [Clock] that abstracts accesses to [DelayController]'s virtual clock. + */ +@OptIn(ExperimentalCoroutinesApi::class) +public class DelayControllerClockAdapter( + private val delayController: DelayController, + private val zone: ZoneId = ZoneId.systemDefault() +) : Clock() { + override fun getZone(): ZoneId = zone + + override fun withZone(zone: ZoneId): Clock = DelayControllerClockAdapter(delayController, zone) + + override fun instant(): Instant = Instant.ofEpochMilli(millis()) + + override fun millis(): Long = delayController.currentTime +} 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/opendc-core/src/main/kotlin/com/atlarge/opendc/core/failure/CorrelatedFaultInjector.kt b/simulator/opendc-simulator/opendc-simulator-failures/src/main/kotlin/org/opendc/simulator/failures/CorrelatedFaultInjector.kt index f77a581e..0e15f338 100644 --- a/simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/failure/CorrelatedFaultInjector.kt +++ b/simulator/opendc-simulator/opendc-simulator-failures/src/main/kotlin/org/opendc/simulator/failures/CorrelatedFaultInjector.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,25 +20,22 @@ * SOFTWARE. */ -package com.atlarge.opendc.core.failure +package org.opendc.simulator.failures -import com.atlarge.odcsim.Domain -import com.atlarge.odcsim.simulationContext +import kotlinx.coroutines.* +import java.time.Clock import kotlin.math.exp import kotlin.math.max import kotlin.random.Random import kotlin.random.asJavaRandom -import kotlinx.coroutines.Job -import kotlinx.coroutines.delay -import kotlinx.coroutines.ensureActive -import kotlinx.coroutines.launch /** * A [FaultInjector] that injects fault in the system which are correlated to each other. Failures do not occur in * isolation, but will trigger other faults. */ public class CorrelatedFaultInjector( - private val domain: Domain, + private val coroutineScope: CoroutineScope, + private val clock: Clock, private val iatScale: Double, private val iatShape: Double, private val sizeScale: Double, @@ -72,7 +67,7 @@ public class CorrelatedFaultInjector( // Clean up the domain if it finishes domain.scope.coroutineContext[Job]!!.invokeOnCompletion { - this@CorrelatedFaultInjector.domain.launch { + this@CorrelatedFaultInjector.coroutineScope.launch { active -= domain if (active.isEmpty()) { @@ -86,7 +81,7 @@ public class CorrelatedFaultInjector( return } - job = this.domain.launch { + job = this.coroutineScope.launch { while (active.isNotEmpty()) { ensureActive() @@ -94,7 +89,7 @@ public class CorrelatedFaultInjector( val d = lognvariate(iatScale, iatShape) * 3.6e6 // Handle long overflow - if (simulationContext.clock.millis() + d <= 0) { + if (clock.millis() + d <= 0) { return@launch } @@ -111,7 +106,7 @@ public class CorrelatedFaultInjector( val df = max(lognvariate(dScale, dShape) * 6e4, 15 * 6e4) // Handle long overflow - if (simulationContext.clock.millis() + df <= 0) { + if (clock.millis() + df <= 0) { return@launch } diff --git a/simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/failure/FailureDomain.kt b/simulator/opendc-simulator/opendc-simulator-failures/src/main/kotlin/org/opendc/simulator/failures/FailureDomain.kt index d56df3c9..dc3006e8 100644 --- a/simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/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 com.atlarge.opendc.core.failure +package org.opendc.simulator.failures import kotlinx.coroutines.CoroutineScope diff --git a/simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/failure/FaultInjector.kt b/simulator/opendc-simulator/opendc-simulator-failures/src/main/kotlin/org/opendc/simulator/failures/FaultInjector.kt index ac7a08de..a866260c 100644 --- a/simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/failure/FaultInjector.kt +++ b/simulator/opendc-simulator/opendc-simulator-failures/src/main/kotlin/org/opendc/simulator/failures/FaultInjector.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 com.atlarge.opendc.core.failure +package org.opendc.simulator.failures /** * An interface for stochastically injecting faults into a running system. diff --git a/simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/failure/UncorrelatedFaultInjector.kt b/simulator/opendc-simulator/opendc-simulator-failures/src/main/kotlin/org/opendc/simulator/failures/UncorrelatedFaultInjector.kt index 0f62667f..b3bd737e 100644 --- a/simulator/opendc/opendc-core/src/main/kotlin/com/atlarge/opendc/core/failure/UncorrelatedFaultInjector.kt +++ b/simulator/opendc-simulator/opendc-simulator-failures/src/main/kotlin/org/opendc/simulator/failures/UncorrelatedFaultInjector.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,20 +20,25 @@ * SOFTWARE. */ -package com.atlarge.opendc.core.failure +package org.opendc.simulator.failures -import com.atlarge.odcsim.simulationContext +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import java.time.Clock import kotlin.math.ln1p import kotlin.math.pow import kotlin.random.Random -import kotlinx.coroutines.delay -import kotlinx.coroutines.launch /** * A [FaultInjector] that injects uncorrelated faults into the system, meaning that failures of the subsystems are * independent. */ -public class UncorrelatedFaultInjector(private val alpha: Double, private val beta: Double, private val random: Random = Random(0)) : FaultInjector { +public class UncorrelatedFaultInjector( + private val clock: Clock, + private val alpha: Double, + private val beta: Double, + private val random: Random = Random(0) +) : FaultInjector { /** * Enqueue the specified [FailureDomain] to fail some time in the future. */ @@ -44,7 +47,7 @@ public class UncorrelatedFaultInjector(private val alpha: Double, private val be val d = random.weibull(alpha, beta) * 1e3 // Make sure to convert delay to milliseconds // Handle long overflow - if (simulationContext.clock.millis() + d <= 0) { + if (clock.millis() + d <= 0) { return@launch } diff --git a/simulator/opendc-utils/build.gradle.kts b/simulator/opendc-utils/build.gradle.kts new file mode 100644 index 00000000..d66148c4 --- /dev/null +++ b/simulator/opendc-utils/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 = "Utilities used across OpenDC modules" + +/* Build configuration */ +plugins { + `kotlin-library-convention` +} + +dependencies { + api("org.jetbrains.kotlinx:kotlinx-coroutines-core:${Library.KOTLINX_COROUTINES}") +} diff --git a/simulator/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/flow/EventFlow.kt b/simulator/opendc-utils/src/main/kotlin/org/opendc/utils/flow/EventFlow.kt index 0e18f82f..948595b1 100644 --- a/simulator/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/flow/EventFlow.kt +++ b/simulator/opendc-utils/src/main/kotlin/org/opendc/utils/flow/EventFlow.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,9 +20,8 @@ * SOFTWARE. */ -package com.atlarge.odcsim.flow +package org.opendc.utils.flow -import java.util.WeakHashMap import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.FlowPreview import kotlinx.coroutines.InternalCoroutinesApi @@ -61,7 +58,7 @@ public fun <T> EventFlow(): EventFlow<T> = EventFlowImpl() @OptIn(ExperimentalCoroutinesApi::class, FlowPreview::class) private class EventFlowImpl<T> : EventFlow<T> { private var closed: Boolean = false - private val subscribers = WeakHashMap<SendChannel<T>, Unit>() + private val subscribers = HashMap<SendChannel<T>, Unit>() override fun emit(event: T) { synchronized(this) { diff --git a/simulator/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/flow/StateFlow.kt b/simulator/opendc-utils/src/main/kotlin/org/opendc/utils/flow/StateFlow.kt index 50add0ad..996e7700 100644 --- a/simulator/odcsim/odcsim-api/src/main/kotlin/com/atlarge/odcsim/flow/StateFlow.kt +++ b/simulator/opendc-utils/src/main/kotlin/org/opendc/utils/flow/StateFlow.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 com.atlarge.odcsim.flow +package org.opendc.utils.flow import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.FlowPreview diff --git a/simulator/opendc/opendc-workflows/build.gradle.kts b/simulator/opendc-workflows/build.gradle.kts index 7a5e2067..f61bdac6 100644 --- a/simulator/opendc/opendc-workflows/build.gradle.kts +++ b/simulator/opendc-workflows/build.gradle.kts @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 atlarge-research + * Copyright (c) 2019 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 @@ -30,12 +28,16 @@ plugins { } dependencies { - api(project(":opendc:opendc-core")) - api(project(":opendc:opendc-compute")) - implementation(kotlin("stdlib")) + api(project(":opendc-core")) + api(project(":opendc-compute:opendc-compute-core")) + implementation(project(":opendc-utils")) - testRuntimeOnly(project(":odcsim:odcsim-engine-omega")) - testImplementation(project(":opendc:opendc-format")) + 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/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/JobState.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/JobState.kt index 1cb2de97..89849f6a 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/JobState.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/JobState.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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,18 +20,18 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service +package org.opendc.workflows.service -import com.atlarge.opendc.workflows.workload.Job +import org.opendc.workflows.workload.Job -class JobState(val job: Job, val submittedAt: Long) { +public class JobState(public val job: Job, public val submittedAt: Long) { /** * A flag to indicate whether this job is finished. */ - val isFinished: Boolean + public val isFinished: Boolean get() = tasks.isEmpty() - val tasks: MutableSet<TaskState> = mutableSetOf() + internal val tasks: MutableSet<TaskState> = mutableSetOf() override fun equals(other: Any?): Boolean = other is JobState && other.job == job diff --git a/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/StageWorkflowSchedulerListener.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/StageWorkflowSchedulerListener.kt new file mode 100644 index 00000000..18721889 --- /dev/null +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/StageWorkflowSchedulerListener.kt @@ -0,0 +1,37 @@ +/* + * 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.workflows.service + +public interface StageWorkflowSchedulerListener { + public fun cycleStarted(scheduler: StageWorkflowService) {} + public fun cycleFinished(scheduler: StageWorkflowService) {} + + public fun jobSubmitted(job: JobState) {} + public fun jobStarted(job: JobState) {} + public fun jobFinished(job: JobState) {} + + public fun taskReady(task: TaskState) {} + public fun taskAssigned(task: TaskState) {} + public fun taskStarted(task: TaskState) {} + public fun taskFinished(task: TaskState) {} +} diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/StageWorkflowService.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/StageWorkflowService.kt index 1193f7b2..3b4e6eab 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/StageWorkflowService.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/StageWorkflowService.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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,39 +20,37 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service - -import com.atlarge.odcsim.Domain -import com.atlarge.odcsim.flow.EventFlow -import com.atlarge.odcsim.simulationContext -import com.atlarge.opendc.compute.core.Server -import com.atlarge.opendc.compute.core.ServerEvent -import com.atlarge.opendc.compute.core.ServerState -import com.atlarge.opendc.compute.metal.Node -import com.atlarge.opendc.compute.metal.service.ProvisioningService -import com.atlarge.opendc.workflows.service.stage.job.JobAdmissionPolicy -import com.atlarge.opendc.workflows.service.stage.job.JobOrderPolicy -import com.atlarge.opendc.workflows.service.stage.resource.ResourceFilterPolicy -import com.atlarge.opendc.workflows.service.stage.resource.ResourceSelectionPolicy -import com.atlarge.opendc.workflows.service.stage.task.TaskEligibilityPolicy -import com.atlarge.opendc.workflows.service.stage.task.TaskOrderPolicy -import com.atlarge.opendc.workflows.workload.Job -import java.util.PriorityQueue -import java.util.Queue +package org.opendc.workflows.service + import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.launchIn import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext +import org.opendc.compute.core.Server +import org.opendc.compute.core.ServerEvent +import org.opendc.compute.core.ServerState +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 +import org.opendc.workflows.service.stage.resource.ResourceFilterPolicy +import org.opendc.workflows.service.stage.resource.ResourceSelectionPolicy +import org.opendc.workflows.service.stage.task.TaskEligibilityPolicy +import org.opendc.workflows.service.stage.task.TaskOrderPolicy +import org.opendc.workflows.workload.Job +import java.time.Clock +import java.util.* /** * A [WorkflowService] that distributes work through a multi-stage process based on the Reference Architecture for * Topology Scheduling. */ -class StageWorkflowService( - private val domain: Domain, +public class StageWorkflowService( + internal val coroutineScope: CoroutineScope, + internal val clock: Clock, private val provisioningService: ProvisioningService, mode: WorkflowSchedulerMode, jobAdmissionPolicy: JobAdmissionPolicy, @@ -63,7 +59,7 @@ class StageWorkflowService( taskOrderPolicy: TaskOrderPolicy, resourceFilterPolicy: ResourceFilterPolicy, resourceSelectionPolicy: ResourceSelectionPolicy -) : WorkflowService, CoroutineScope by domain { +) : WorkflowService { /** * The incoming jobs ready to be processed by the scheduler. @@ -175,7 +171,7 @@ class StageWorkflowService( private val eventFlow = EventFlow<WorkflowEvent>() init { - domain.launch { + coroutineScope.launch { nodes = provisioningService.nodes().toList() available.addAll(nodes) } @@ -191,9 +187,9 @@ class StageWorkflowService( override val events: Flow<WorkflowEvent> = eventFlow - override suspend fun submit(job: Job) = withContext(domain.coroutineContext) { + override suspend fun submit(job: Job) { // J1 Incoming Jobs - val jobInstance = JobState(job, simulationContext.clock.millis()) + val jobInstance = JobState(job, clock.millis()) val instances = job.tasks.associateWith { TaskState(jobInstance, it) } @@ -241,7 +237,7 @@ class StageWorkflowService( iterator.remove() jobQueue.add(jobInstance) activeJobs += jobInstance - eventFlow.emit(WorkflowEvent.JobStarted(this, jobInstance.job, simulationContext.clock.millis())) + eventFlow.emit(WorkflowEvent.JobStarted(this, jobInstance.job, clock.millis())) rootListener.jobStarted(jobInstance) } @@ -295,7 +291,7 @@ class StageWorkflowService( taskByServer[server] = instance server.events .onEach { event -> if (event is ServerEvent.StateChanged) stateChanged(event.server) } - .launchIn(this) + .launchIn(coroutineScope) activeTasks += instance taskQueue.poll() @@ -310,19 +306,33 @@ class StageWorkflowService( when (server.state) { ServerState.ACTIVE -> { val task = taskByServer.getValue(server) - task.startedAt = simulationContext.clock.millis() - eventFlow.emit(WorkflowEvent.TaskStarted(this@StageWorkflowService, task.job.job, task.task, simulationContext.clock.millis())) + task.startedAt = clock.millis() + eventFlow.emit( + WorkflowEvent.TaskStarted( + this@StageWorkflowService, + task.job.job, + task.task, + clock.millis() + ) + ) rootListener.taskStarted(task) } ServerState.SHUTOFF, ServerState.ERROR -> { val task = taskByServer.remove(server) ?: throw IllegalStateException() val job = task.job task.state = TaskStatus.FINISHED - task.finishedAt = simulationContext.clock.millis() + task.finishedAt = clock.millis() job.tasks.remove(task) available += task.host!! activeTasks -= task - eventFlow.emit(WorkflowEvent.TaskFinished(this@StageWorkflowService, task.job.job, task.task, simulationContext.clock.millis())) + eventFlow.emit( + WorkflowEvent.TaskFinished( + this@StageWorkflowService, + task.job.job, + task.task, + clock.millis() + ) + ) rootListener.taskFinished(task) // Add job roots to the scheduling queue @@ -347,15 +357,15 @@ class StageWorkflowService( private suspend fun finishJob(job: JobState) { activeJobs -= job - eventFlow.emit(WorkflowEvent.JobFinished(this, job.job, simulationContext.clock.millis())) + eventFlow.emit(WorkflowEvent.JobFinished(this, job.job, clock.millis())) rootListener.jobFinished(job) } - fun addListener(listener: StageWorkflowSchedulerListener) { + public fun addListener(listener: StageWorkflowSchedulerListener) { rootListener.listeners += listener } - fun removeListener(listener: StageWorkflowSchedulerListener) { + public fun removeListener(listener: StageWorkflowSchedulerListener) { rootListener.listeners -= listener } } diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/TaskState.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/TaskState.kt index acd5731b..ed023c82 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/TaskState.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/TaskState.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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,39 +20,39 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service +package org.opendc.workflows.service -import com.atlarge.opendc.compute.metal.Node -import com.atlarge.opendc.workflows.workload.Task +import org.opendc.compute.core.metal.Node +import org.opendc.workflows.workload.Task -class TaskState(val job: JobState, val task: Task) { +public class TaskState(public val job: JobState, public val task: Task) { /** * The moment in time the task was started. */ - var startedAt: Long = Long.MIN_VALUE + public var startedAt: Long = Long.MIN_VALUE /** * The moment in time the task was finished. */ - var finishedAt: Long = Long.MIN_VALUE + public var finishedAt: Long = Long.MIN_VALUE /** * The dependencies of this task. */ - val dependencies = HashSet<TaskState>() + public val dependencies: HashSet<TaskState> = HashSet<TaskState>() /** * The dependents of this task. */ - val dependents = HashSet<TaskState>() + public val dependents: HashSet<TaskState> = HashSet<TaskState>() /** * A flag to indicate whether this workflow task instance is a workflow root. */ - val isRoot: Boolean + public val isRoot: Boolean get() = dependencies.isEmpty() - var state: TaskStatus = TaskStatus.CREATED + public var state: TaskStatus = TaskStatus.CREATED set(value) { field = value @@ -64,7 +62,7 @@ class TaskState(val job: JobState, val task: Task) { } } - var host: Node? = null + public var host: Node? = null /** * Mark the specified [TaskView] as terminated. diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/TaskStatus.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/TaskStatus.kt index c53c6171..99f5bb87 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/TaskStatus.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/TaskStatus.kt @@ -22,7 +22,7 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service +package org.opendc.workflows.service /** * The state of a workflow task. diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/WorkflowEvent.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/WorkflowEvent.kt index 2ca5a19d..dadccb50 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/WorkflowEvent.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/WorkflowEvent.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,10 +20,10 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service +package org.opendc.workflows.service -import com.atlarge.opendc.workflows.workload.Job -import com.atlarge.opendc.workflows.workload.Task +import org.opendc.workflows.workload.Job +import org.opendc.workflows.workload.Task /** * An event emitted by the [WorkflowService]. diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/WorkflowSchedulerMode.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/WorkflowSchedulerMode.kt index 776f0b07..d03adc61 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/WorkflowSchedulerMode.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/WorkflowSchedulerMode.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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,32 +20,31 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service +package org.opendc.workflows.service -import com.atlarge.odcsim.simulationContext -import com.atlarge.opendc.workflows.service.stage.StagePolicy import kotlinx.coroutines.delay import kotlinx.coroutines.launch import kotlinx.coroutines.yield +import org.opendc.workflows.service.stage.StagePolicy /** * The operating mode of a workflow scheduler. */ -sealed class WorkflowSchedulerMode : StagePolicy<WorkflowSchedulerMode.Logic> { +public sealed class WorkflowSchedulerMode : StagePolicy<WorkflowSchedulerMode.Logic> { /** * The logic for operating the cycles of a workflow scheduler. */ - interface Logic { + public interface Logic { /** * Request a new scheduling cycle to be performed. */ - suspend fun requestCycle() + public suspend fun requestCycle() } /** * An interactive scheduler immediately triggers a new scheduling cycle when a workflow is received. */ - object Interactive : WorkflowSchedulerMode() { + public object Interactive : WorkflowSchedulerMode() { override fun invoke(scheduler: StageWorkflowService): Logic = object : Logic { override suspend fun requestCycle() { yield() @@ -61,18 +58,17 @@ sealed class WorkflowSchedulerMode : StagePolicy<WorkflowSchedulerMode.Logic> { /** * A batch scheduler triggers a scheduling cycle every time quantum if needed. */ - data class Batch(val quantum: Long) : WorkflowSchedulerMode() { + public data class Batch(val quantum: Long) : WorkflowSchedulerMode() { private var next: kotlinx.coroutines.Job? = null override fun invoke(scheduler: StageWorkflowService): Logic = object : Logic { override suspend fun requestCycle() { - val ctx = simulationContext if (next == null) { // In batch mode, we assume that the scheduler runs at a fixed slot every time // quantum (e.g t=0, t=60, t=120). We calculate here the delay until the next scheduling slot. - val delay = quantum - (ctx.clock.millis() % quantum) + val delay = quantum - (scheduler.clock.millis() % quantum) - val job = ctx.domain.launch { + val job = scheduler.coroutineScope.launch { delay(delay) next = null scheduler.schedule() @@ -88,16 +84,15 @@ sealed class WorkflowSchedulerMode : StagePolicy<WorkflowSchedulerMode.Logic> { /** * A scheduling cycle is triggered at a random point in time. */ - data class Random(private val random: java.util.Random = java.util.Random(123)) : WorkflowSchedulerMode() { + public data class Random(private val random: java.util.Random = java.util.Random(123)) : WorkflowSchedulerMode() { private var next: kotlinx.coroutines.Job? = null override fun invoke(scheduler: StageWorkflowService): Logic = object : Logic { override suspend fun requestCycle() { - val ctx = simulationContext if (next == null) { val delay = random.nextInt(200).toLong() - val job = ctx.domain.launch { + val job = scheduler.coroutineScope.launch { delay(delay) next = null scheduler.schedule() diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/WorkflowService.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/WorkflowService.kt index a60ba0e2..319a8b85 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/WorkflowService.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/WorkflowService.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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,12 +20,12 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service +package org.opendc.workflows.service -import com.atlarge.opendc.core.services.AbstractServiceKey -import com.atlarge.opendc.workflows.workload.Job -import java.util.UUID import kotlinx.coroutines.flow.Flow +import org.opendc.core.services.AbstractServiceKey +import org.opendc.workflows.workload.Job +import java.util.* /** * A service for cloud workflow management. @@ -48,5 +46,5 @@ public interface WorkflowService { /** * The service key for the workflow scheduler. */ - companion object Key : AbstractServiceKey<WorkflowService>(UUID.randomUUID(), "workflows") + public companion object Key : AbstractServiceKey<WorkflowService>(UUID.randomUUID(), "workflows") } diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/StagePolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/StagePolicy.kt index c7cc3d84..d76579f9 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/StagePolicy.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/StagePolicy.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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,17 +20,17 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service.stage +package org.opendc.workflows.service.stage -import com.atlarge.opendc.workflows.service.StageWorkflowService +import org.opendc.workflows.service.StageWorkflowService import java.io.Serializable /** * A scheduling stage policy. */ -interface StagePolicy<T : Any> : Serializable { +public interface StagePolicy<T : Any> : Serializable { /** * Build the logic of the stage policy. */ - operator fun invoke(scheduler: StageWorkflowService): T + public operator fun invoke(scheduler: StageWorkflowService): T } diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/job/DurationJobOrderPolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/job/DurationJobOrderPolicy.kt index bbdb9f71..1190a408 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/job/DurationJobOrderPolicy.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/job/DurationJobOrderPolicy.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,19 +20,19 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service.stage.job +package org.opendc.workflows.service.stage.job -import com.atlarge.opendc.workflows.service.JobState -import com.atlarge.opendc.workflows.service.StageWorkflowSchedulerListener -import com.atlarge.opendc.workflows.service.StageWorkflowService -import com.atlarge.opendc.workflows.workload.Job -import com.atlarge.opendc.workflows.workload.Task -import com.atlarge.opendc.workflows.workload.WORKFLOW_TASK_DEADLINE +import org.opendc.workflows.service.JobState +import org.opendc.workflows.service.StageWorkflowSchedulerListener +import org.opendc.workflows.service.StageWorkflowService +import org.opendc.workflows.workload.Job +import org.opendc.workflows.workload.Task +import org.opendc.workflows.workload.WORKFLOW_TASK_DEADLINE /** * A [JobOrderPolicy] that orders jobs based on its critical path length. */ -data class DurationJobOrderPolicy(val ascending: Boolean = true) : JobOrderPolicy { +public data class DurationJobOrderPolicy(val ascending: Boolean = true) : JobOrderPolicy { override fun invoke(scheduler: StageWorkflowService): Comparator<JobState> = object : Comparator<JobState>, StageWorkflowSchedulerListener { private val results = HashMap<Job, Long>() @@ -72,7 +70,7 @@ data class DurationJobOrderPolicy(val ascending: Boolean = true) : JobOrderPolic * * @return The list of tasks within the job topologically sorted. */ -fun Job.toposort(): List<Task> { +public fun Job.toposort(): List<Task> { val res = mutableListOf<Task>() val visited = mutableSetOf<Task>() val adjacent = mutableMapOf<Task, MutableList<Task>>() diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/job/JobAdmissionPolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/job/JobAdmissionPolicy.kt index 535d7792..0e5a42c0 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/job/JobAdmissionPolicy.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/job/JobAdmissionPolicy.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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,23 +20,23 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service.stage.job +package org.opendc.workflows.service.stage.job -import com.atlarge.opendc.workflows.service.JobState -import com.atlarge.opendc.workflows.service.stage.StagePolicy +import org.opendc.workflows.service.JobState +import org.opendc.workflows.service.stage.StagePolicy /** * A policy interface for admitting [JobState]s to a scheduling cycle. */ -interface JobAdmissionPolicy : StagePolicy<JobAdmissionPolicy.Logic> { - interface Logic { +public interface JobAdmissionPolicy : StagePolicy<JobAdmissionPolicy.Logic> { + public interface Logic { /** * Determine whether the specified [JobState] should be admitted to the scheduling cycle. * * @param job The workflow that has been submitted. * @return The advice for admitting the job. */ - operator fun invoke(job: JobState): Advice + public operator fun invoke(job: JobState): Advice } /** @@ -48,7 +46,7 @@ interface JobAdmissionPolicy : StagePolicy<JobAdmissionPolicy.Logic> { * @property stop A flag to indicate the scheduler should immediately stop admitting jobs to the scheduling queue and wait * for the next scheduling cycle. */ - enum class Advice(val admit: Boolean, val stop: Boolean) { + public enum class Advice(public val admit: Boolean, public val stop: Boolean) { /** * Admit the current job to the scheduling queue and continue admitting jobs. */ diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/job/JobOrderPolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/job/JobOrderPolicy.kt index ba57f064..83d42b2d 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/job/JobOrderPolicy.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/job/JobOrderPolicy.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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,12 +20,12 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service.stage.job +package org.opendc.workflows.service.stage.job -import com.atlarge.opendc.workflows.service.JobState -import com.atlarge.opendc.workflows.service.stage.StagePolicy +import org.opendc.workflows.service.JobState +import org.opendc.workflows.service.stage.StagePolicy /** * A policy interface for ordering admitted workflows in the scheduling queue. */ -interface JobOrderPolicy : StagePolicy<Comparator<JobState>> +public interface JobOrderPolicy : StagePolicy<Comparator<JobState>> diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/job/LimitJobAdmissionPolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/job/LimitJobAdmissionPolicy.kt index 6b1faf20..6f6ccb50 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/job/LimitJobAdmissionPolicy.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/job/LimitJobAdmissionPolicy.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,18 +20,18 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service.stage.job +package org.opendc.workflows.service.stage.job -import com.atlarge.opendc.workflows.service.JobState -import com.atlarge.opendc.workflows.service.StageWorkflowService +import org.opendc.workflows.service.JobState +import org.opendc.workflows.service.StageWorkflowService /** * A [JobAdmissionPolicy] that limits the amount of active jobs in the system. * * @property limit The maximum number of concurrent jobs in the system. */ -data class LimitJobAdmissionPolicy(val limit: Int) : JobAdmissionPolicy { - override fun invoke(scheduler: StageWorkflowService) = object : JobAdmissionPolicy.Logic { +public data class LimitJobAdmissionPolicy(public val limit: Int) : JobAdmissionPolicy { + override fun invoke(scheduler: StageWorkflowService): JobAdmissionPolicy.Logic = object : JobAdmissionPolicy.Logic { override fun invoke( job: JobState ): JobAdmissionPolicy.Advice = diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/job/LoadJobAdmissionPolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/job/LoadJobAdmissionPolicy.kt index e1c27472..4f0c269a 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/job/LoadJobAdmissionPolicy.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/job/LoadJobAdmissionPolicy.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,18 +20,18 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service.stage.job +package org.opendc.workflows.service.stage.job -import com.atlarge.opendc.workflows.service.JobState -import com.atlarge.opendc.workflows.service.StageWorkflowService +import org.opendc.workflows.service.JobState +import org.opendc.workflows.service.StageWorkflowService /** * A [JobAdmissionPolicy] that limits the amount of jobs based on the average system load. * * @property limit The maximum load before stopping admission. */ -data class LoadJobAdmissionPolicy(val limit: Double) : JobAdmissionPolicy { - override fun invoke(scheduler: StageWorkflowService) = object : JobAdmissionPolicy.Logic { +public data class LoadJobAdmissionPolicy(public val limit: Double) : JobAdmissionPolicy { + override fun invoke(scheduler: StageWorkflowService): JobAdmissionPolicy.Logic = object : JobAdmissionPolicy.Logic { override fun invoke( job: JobState ): JobAdmissionPolicy.Advice = diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/job/NullJobAdmissionPolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/job/NullJobAdmissionPolicy.kt index 46888467..ac74f090 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/job/NullJobAdmissionPolicy.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/job/NullJobAdmissionPolicy.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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,16 +20,16 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service.stage.job +package org.opendc.workflows.service.stage.job -import com.atlarge.opendc.workflows.service.JobState -import com.atlarge.opendc.workflows.service.StageWorkflowService +import org.opendc.workflows.service.JobState +import org.opendc.workflows.service.StageWorkflowService /** * A [JobAdmissionPolicy] that admits all jobs. */ -object NullJobAdmissionPolicy : JobAdmissionPolicy { - override fun invoke(scheduler: StageWorkflowService) = object : JobAdmissionPolicy.Logic { +public object NullJobAdmissionPolicy : JobAdmissionPolicy { + override fun invoke(scheduler: StageWorkflowService): JobAdmissionPolicy.Logic = object : JobAdmissionPolicy.Logic { override fun invoke(job: JobState): JobAdmissionPolicy.Advice = JobAdmissionPolicy.Advice.ADMIT } diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/job/RandomJobOrderPolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/job/RandomJobOrderPolicy.kt index 14a3d98d..6c747261 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/job/RandomJobOrderPolicy.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/job/RandomJobOrderPolicy.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,18 +20,21 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service.stage.job +package org.opendc.workflows.service.stage.job -import com.atlarge.opendc.workflows.service.JobState -import com.atlarge.opendc.workflows.service.StageWorkflowSchedulerListener -import com.atlarge.opendc.workflows.service.StageWorkflowService -import com.atlarge.opendc.workflows.workload.Job -import java.util.Random +import org.opendc.workflows.service.JobState +import org.opendc.workflows.service.StageWorkflowSchedulerListener +import org.opendc.workflows.service.StageWorkflowService +import org.opendc.workflows.workload.Job +import java.util.* +import kotlin.collections.HashMap +import kotlin.collections.getValue +import kotlin.collections.set /** * A [JobOrderPolicy] that randomly orders jobs. */ -object RandomJobOrderPolicy : JobOrderPolicy { +public object RandomJobOrderPolicy : JobOrderPolicy { override fun invoke(scheduler: StageWorkflowService): Comparator<JobState> = object : Comparator<JobState>, StageWorkflowSchedulerListener { private val random = Random(123) diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/job/SizeJobOrderPolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/job/SizeJobOrderPolicy.kt index 3bce43cf..c1c244c3 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/job/SizeJobOrderPolicy.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/job/SizeJobOrderPolicy.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,17 +20,17 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service.stage.job +package org.opendc.workflows.service.stage.job -import com.atlarge.opendc.workflows.service.JobState -import com.atlarge.opendc.workflows.service.StageWorkflowService +import org.opendc.workflows.service.JobState +import org.opendc.workflows.service.StageWorkflowService /** * A [SizeJobOrderPolicy] that orders jobs based on the number of tasks it has. */ -data class SizeJobOrderPolicy(val ascending: Boolean = true) : JobOrderPolicy { - override fun invoke(scheduler: StageWorkflowService) = - compareBy<JobState> { it.tasks.size.let { if (ascending) it else -it } } +public data class SizeJobOrderPolicy(public val ascending: Boolean = true) : JobOrderPolicy { + override fun invoke(scheduler: StageWorkflowService): Comparator<JobState> = + compareBy { it.tasks.size.let { if (ascending) it else -it } } override fun toString(): String { return "Job-Size(${if (ascending) "asc" else "desc"})" diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/job/SubmissionTimeJobOrderPolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/job/SubmissionTimeJobOrderPolicy.kt index d6e24b2b..005f8153 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/job/SubmissionTimeJobOrderPolicy.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/job/SubmissionTimeJobOrderPolicy.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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,17 +20,17 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service.stage.job +package org.opendc.workflows.service.stage.job -import com.atlarge.opendc.workflows.service.JobState -import com.atlarge.opendc.workflows.service.StageWorkflowService +import org.opendc.workflows.service.JobState +import org.opendc.workflows.service.StageWorkflowService /** * A [JobOrderPolicy] orders jobs in FIFO order. */ -data class SubmissionTimeJobOrderPolicy(val ascending: Boolean = true) : JobOrderPolicy { - override fun invoke(scheduler: StageWorkflowService) = - compareBy<JobState> { it.submittedAt.let { if (ascending) it else -it } } +public data class SubmissionTimeJobOrderPolicy(public val ascending: Boolean = true) : JobOrderPolicy { + override fun invoke(scheduler: StageWorkflowService): Comparator<JobState> = + compareBy { it.submittedAt.let { if (ascending) it else -it } } override fun toString(): String { return "Submission-Time(${if (ascending) "asc" else "desc"})" diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/resource/FirstFitResourceSelectionPolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/FirstFitResourceSelectionPolicy.kt index a5671d45..8dc323ec 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/resource/FirstFitResourceSelectionPolicy.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/FirstFitResourceSelectionPolicy.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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,18 +20,17 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service.stage.resource +package org.opendc.workflows.service.stage.resource -import com.atlarge.opendc.compute.metal.Node -import com.atlarge.opendc.workflows.service.StageWorkflowService +import org.opendc.compute.core.metal.Node +import org.opendc.workflows.service.StageWorkflowService /** * A [ResourceSelectionPolicy] that selects the first machine that is available. */ -object FirstFitResourceSelectionPolicy : ResourceSelectionPolicy { - override fun invoke(scheduler: StageWorkflowService) = object : Comparator<Node> { - override fun compare(o1: Node, o2: Node): Int = 1 - } +public object FirstFitResourceSelectionPolicy : ResourceSelectionPolicy { + override fun invoke(scheduler: StageWorkflowService): Comparator<Node> = + Comparator<Node> { _, _ -> 1 } override fun toString(): String = "First-Fit" } diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/resource/FunctionalResourceFilterPolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/FunctionalResourceFilterPolicy.kt index 0e83d8d7..ac79a9ce 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/resource/FunctionalResourceFilterPolicy.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/FunctionalResourceFilterPolicy.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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,17 +20,17 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service.stage.resource +package org.opendc.workflows.service.stage.resource -import com.atlarge.opendc.compute.metal.Node -import com.atlarge.opendc.workflows.service.StageWorkflowService -import com.atlarge.opendc.workflows.service.TaskState +import org.opendc.compute.core.metal.Node +import org.opendc.workflows.service.StageWorkflowService +import org.opendc.workflows.service.TaskState /** * A [ResourceFilterPolicy] based on the amount of cores available on the machine and the cores required for * the task. */ -object FunctionalResourceFilterPolicy : ResourceFilterPolicy { +public object FunctionalResourceFilterPolicy : ResourceFilterPolicy { override fun invoke(scheduler: StageWorkflowService): ResourceFilterPolicy.Logic = object : ResourceFilterPolicy.Logic { override fun invoke(hosts: Sequence<Node>, task: TaskState): Sequence<Node> = diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/resource/RandomResourceSelectionPolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/RandomResourceSelectionPolicy.kt index 9b05cbac..caf87c70 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/resource/RandomResourceSelectionPolicy.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/RandomResourceSelectionPolicy.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,17 +20,17 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service.stage.resource +package org.opendc.workflows.service.stage.resource -import com.atlarge.opendc.compute.metal.Node -import com.atlarge.opendc.workflows.service.StageWorkflowService -import java.util.Random +import org.opendc.compute.core.metal.Node +import org.opendc.workflows.service.StageWorkflowService +import java.util.* /** * A [ResourceSelectionPolicy] that randomly orders the machines. */ -object RandomResourceSelectionPolicy : ResourceSelectionPolicy { - override fun invoke(scheduler: StageWorkflowService) = object : Comparator<Node> { +public object RandomResourceSelectionPolicy : ResourceSelectionPolicy { + override fun invoke(scheduler: StageWorkflowService): Comparator<Node> = object : Comparator<Node> { private val ids: Map<Node, Long> init { diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/resource/ResourceFilterPolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/ResourceFilterPolicy.kt index 28ef970f..4923a34b 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/resource/ResourceFilterPolicy.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/ResourceFilterPolicy.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,19 +20,19 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service.stage.resource +package org.opendc.workflows.service.stage.resource -import com.atlarge.opendc.compute.metal.Node -import com.atlarge.opendc.workflows.service.TaskState -import com.atlarge.opendc.workflows.service.stage.StagePolicy +import org.opendc.compute.core.metal.Node +import org.opendc.workflows.service.TaskState +import org.opendc.workflows.service.stage.StagePolicy /** * This interface represents stages **R2**, **R3** and **R4** stage of the Reference Architecture for Schedulers and * acts as a filter yielding a list of resources with sufficient resource-capacities, based on fixed or dynamic * requirements, and on predicted or monitored information about processing unit availability, memory occupancy, etc. */ -interface ResourceFilterPolicy : StagePolicy<ResourceFilterPolicy.Logic> { - interface Logic { +public interface ResourceFilterPolicy : StagePolicy<ResourceFilterPolicy.Logic> { + public interface Logic { /** * Filter the list of machines based on dynamic information. * @@ -42,6 +40,6 @@ interface ResourceFilterPolicy : StagePolicy<ResourceFilterPolicy.Logic> { * @param task The task that is to be scheduled. * @return The machines on which the task can be scheduled. */ - operator fun invoke(hosts: Sequence<Node>, task: TaskState): Sequence<Node> + public operator fun invoke(hosts: Sequence<Node>, task: TaskState): Sequence<Node> } } diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/resource/ResourceSelectionPolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/ResourceSelectionPolicy.kt index 43053097..990b990a 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/resource/ResourceSelectionPolicy.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/resource/ResourceSelectionPolicy.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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,13 +20,13 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service.stage.resource +package org.opendc.workflows.service.stage.resource -import com.atlarge.opendc.compute.metal.Node -import com.atlarge.opendc.workflows.service.stage.StagePolicy +import org.opendc.compute.core.metal.Node +import org.opendc.workflows.service.stage.StagePolicy /** * This interface represents the **R5** stage of the Reference Architecture for Schedulers and matches the the selected * task with a (set of) resource(s), using policies such as First-Fit, Worst-Fit, and Best-Fit. */ -interface ResourceSelectionPolicy : StagePolicy<Comparator<Node>> +public interface ResourceSelectionPolicy : StagePolicy<Comparator<Node>> diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/ActiveTaskOrderPolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/ActiveTaskOrderPolicy.kt index b084d26c..6a465746 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/ActiveTaskOrderPolicy.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/ActiveTaskOrderPolicy.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,17 +20,17 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service.stage.task +package org.opendc.workflows.service.stage.task -import com.atlarge.opendc.workflows.service.JobState -import com.atlarge.opendc.workflows.service.StageWorkflowSchedulerListener -import com.atlarge.opendc.workflows.service.StageWorkflowService -import com.atlarge.opendc.workflows.service.TaskState +import org.opendc.workflows.service.JobState +import org.opendc.workflows.service.StageWorkflowSchedulerListener +import org.opendc.workflows.service.StageWorkflowService +import org.opendc.workflows.service.TaskState /** * A [TaskOrderPolicy] that orders tasks based on the number of active relative tasks (w.r.t. its job) in the system. */ -data class ActiveTaskOrderPolicy(val ascending: Boolean = true) : TaskOrderPolicy { +public data class ActiveTaskOrderPolicy(public val ascending: Boolean = true) : TaskOrderPolicy { override fun invoke(scheduler: StageWorkflowService): Comparator<TaskState> = object : Comparator<TaskState>, StageWorkflowSchedulerListener { private val active = mutableMapOf<JobState, Int>() diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/BalancingTaskEligibilityPolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/BalancingTaskEligibilityPolicy.kt index 2255d40c..f3f19ef5 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/BalancingTaskEligibilityPolicy.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/BalancingTaskEligibilityPolicy.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,12 +20,12 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service.stage.task +package org.opendc.workflows.service.stage.task -import com.atlarge.opendc.workflows.service.JobState -import com.atlarge.opendc.workflows.service.StageWorkflowSchedulerListener -import com.atlarge.opendc.workflows.service.StageWorkflowService -import com.atlarge.opendc.workflows.service.TaskState +import org.opendc.workflows.service.JobState +import org.opendc.workflows.service.StageWorkflowSchedulerListener +import org.opendc.workflows.service.StageWorkflowService +import org.opendc.workflows.service.TaskState import kotlin.math.max /** @@ -37,7 +35,7 @@ import kotlin.math.max * @property tolerance The maximum difference from the average number of tasks per job in the system as a fraction of * the average. */ -data class BalancingTaskEligibilityPolicy(val tolerance: Double = 1.5) : TaskEligibilityPolicy { +public data class BalancingTaskEligibilityPolicy(public val tolerance: Double = 1.5) : TaskEligibilityPolicy { override fun invoke(scheduler: StageWorkflowService): TaskEligibilityPolicy.Logic = object : TaskEligibilityPolicy.Logic, StageWorkflowSchedulerListener { private val active = mutableMapOf<JobState, Int>() diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/CompletionTaskOrderPolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/CompletionTaskOrderPolicy.kt index d0cf1374..0020023f 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/CompletionTaskOrderPolicy.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/CompletionTaskOrderPolicy.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,17 +20,17 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service.stage.task +package org.opendc.workflows.service.stage.task -import com.atlarge.opendc.workflows.service.JobState -import com.atlarge.opendc.workflows.service.StageWorkflowSchedulerListener -import com.atlarge.opendc.workflows.service.StageWorkflowService -import com.atlarge.opendc.workflows.service.TaskState +import org.opendc.workflows.service.JobState +import org.opendc.workflows.service.StageWorkflowSchedulerListener +import org.opendc.workflows.service.StageWorkflowService +import org.opendc.workflows.service.TaskState /** * A [TaskOrderPolicy] that orders tasks based on the number of completed relative tasks. */ -data class CompletionTaskOrderPolicy(val ascending: Boolean = true) : TaskOrderPolicy { +public data class CompletionTaskOrderPolicy(public val ascending: Boolean = true) : TaskOrderPolicy { override fun invoke(scheduler: StageWorkflowService): Comparator<TaskState> = object : Comparator<TaskState>, StageWorkflowSchedulerListener { private val finished = mutableMapOf<JobState, Int>() diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/DependenciesTaskOrderPolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/DependenciesTaskOrderPolicy.kt index 73d83d21..a9f5eb84 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/DependenciesTaskOrderPolicy.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/DependenciesTaskOrderPolicy.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,16 +20,16 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service.stage.task +package org.opendc.workflows.service.stage.task -import com.atlarge.opendc.workflows.service.StageWorkflowService -import com.atlarge.opendc.workflows.service.TaskState +import org.opendc.workflows.service.StageWorkflowService +import org.opendc.workflows.service.TaskState /** * A [TaskOrderPolicy] that orders tasks based on the number of dependency tasks it has. */ -data class DependenciesTaskOrderPolicy(val ascending: Boolean = true) : TaskOrderPolicy { - override fun invoke(scheduler: StageWorkflowService) = compareBy<TaskState> { +public data class DependenciesTaskOrderPolicy(public val ascending: Boolean = true) : TaskOrderPolicy { + override fun invoke(scheduler: StageWorkflowService): Comparator<TaskState> = compareBy<TaskState> { it.task.dependencies.size.let { if (ascending) it else -it } } diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/DependentsTaskOrderPolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/DependentsTaskOrderPolicy.kt index 85b3543f..e5a9f159 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/DependentsTaskOrderPolicy.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/DependentsTaskOrderPolicy.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,16 +20,16 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service.stage.task +package org.opendc.workflows.service.stage.task -import com.atlarge.opendc.workflows.service.StageWorkflowService -import com.atlarge.opendc.workflows.service.TaskState +import org.opendc.workflows.service.StageWorkflowService +import org.opendc.workflows.service.TaskState /** * A [TaskOrderPolicy] that orders tasks based on the number of dependent tasks it has. */ -data class DependentsTaskOrderPolicy(val ascending: Boolean = true) : TaskOrderPolicy { - override fun invoke(scheduler: StageWorkflowService) = compareBy<TaskState> { +public data class DependentsTaskOrderPolicy(public val ascending: Boolean = true) : TaskOrderPolicy { + override fun invoke(scheduler: StageWorkflowService): Comparator<TaskState> = compareBy<TaskState> { it.dependents.size.let { if (ascending) it else -it } } diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/DurationHistoryTaskOrderPolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/DurationHistoryTaskOrderPolicy.kt index 426a76a4..7ce8ccce 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/DurationHistoryTaskOrderPolicy.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/DurationHistoryTaskOrderPolicy.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,18 +20,17 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service.stage.task +package org.opendc.workflows.service.stage.task -import com.atlarge.opendc.workflows.service.JobState -import com.atlarge.opendc.workflows.service.StageWorkflowSchedulerListener -import com.atlarge.opendc.workflows.service.StageWorkflowService -import com.atlarge.opendc.workflows.service.TaskState +import org.opendc.workflows.service.JobState +import org.opendc.workflows.service.StageWorkflowSchedulerListener +import org.opendc.workflows.service.StageWorkflowService +import org.opendc.workflows.service.TaskState /** * A [TaskOrderPolicy] that orders tasks based on the average duration of the preceding tasks in the job. */ -data class DurationHistoryTaskOrderPolicy(val ascending: Boolean = true) : TaskOrderPolicy { - +public data class DurationHistoryTaskOrderPolicy(public val ascending: Boolean = true) : TaskOrderPolicy { override fun invoke(scheduler: StageWorkflowService): Comparator<TaskState> = object : Comparator<TaskState>, StageWorkflowSchedulerListener { private val results = HashMap<JobState, MutableList<Long>>() diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/DurationTaskOrderPolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/DurationTaskOrderPolicy.kt index 23b47891..3674eb01 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/DurationTaskOrderPolicy.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/DurationTaskOrderPolicy.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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,18 +20,22 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service.stage.task +package org.opendc.workflows.service.stage.task -import com.atlarge.opendc.workflows.service.StageWorkflowSchedulerListener -import com.atlarge.opendc.workflows.service.StageWorkflowService -import com.atlarge.opendc.workflows.service.TaskState -import com.atlarge.opendc.workflows.workload.WORKFLOW_TASK_DEADLINE -import java.util.UUID +import org.opendc.workflows.service.StageWorkflowSchedulerListener +import org.opendc.workflows.service.StageWorkflowService +import org.opendc.workflows.service.TaskState +import org.opendc.workflows.workload.WORKFLOW_TASK_DEADLINE +import java.util.* +import kotlin.collections.HashMap +import kotlin.collections.getValue +import kotlin.collections.minusAssign +import kotlin.collections.set /** * A [TaskOrderPolicy] orders tasks based on the pre-specified (approximate) duration of the task. */ -data class DurationTaskOrderPolicy(val ascending: Boolean = true) : TaskOrderPolicy { +public data class DurationTaskOrderPolicy(public val ascending: Boolean = true) : TaskOrderPolicy { override fun invoke(scheduler: StageWorkflowService): Comparator<TaskState> = object : Comparator<TaskState>, StageWorkflowSchedulerListener { diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/LimitPerJobTaskEligibilityPolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/LimitPerJobTaskEligibilityPolicy.kt index c039bf6f..2dddbc7c 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/LimitPerJobTaskEligibilityPolicy.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/LimitPerJobTaskEligibilityPolicy.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,17 +20,17 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service.stage.task +package org.opendc.workflows.service.stage.task -import com.atlarge.opendc.workflows.service.JobState -import com.atlarge.opendc.workflows.service.StageWorkflowSchedulerListener -import com.atlarge.opendc.workflows.service.StageWorkflowService -import com.atlarge.opendc.workflows.service.TaskState +import org.opendc.workflows.service.JobState +import org.opendc.workflows.service.StageWorkflowSchedulerListener +import org.opendc.workflows.service.StageWorkflowService +import org.opendc.workflows.service.TaskState /** * A [TaskEligibilityPolicy] that limits the number of active tasks of a job in the system. */ -data class LimitPerJobTaskEligibilityPolicy(val limit: Int) : TaskEligibilityPolicy { +public data class LimitPerJobTaskEligibilityPolicy(public val limit: Int) : TaskEligibilityPolicy { override fun invoke(scheduler: StageWorkflowService): TaskEligibilityPolicy.Logic = object : TaskEligibilityPolicy.Logic, StageWorkflowSchedulerListener { private val active = mutableMapOf<JobState, Int>() diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/LimitTaskEligibilityPolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/LimitTaskEligibilityPolicy.kt index 75322ef5..fdc1fd5e 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/LimitTaskEligibilityPolicy.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/LimitTaskEligibilityPolicy.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,16 +20,16 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service.stage.task +package org.opendc.workflows.service.stage.task -import com.atlarge.opendc.workflows.service.StageWorkflowService -import com.atlarge.opendc.workflows.service.TaskState +import org.opendc.workflows.service.StageWorkflowService +import org.opendc.workflows.service.TaskState /** * A [TaskEligibilityPolicy] that limits the total number of active tasks in the system. */ -data class LimitTaskEligibilityPolicy(val limit: Int) : TaskEligibilityPolicy { - override fun invoke(scheduler: StageWorkflowService) = object : TaskEligibilityPolicy.Logic { +public data class LimitTaskEligibilityPolicy(val limit: Int) : TaskEligibilityPolicy { + override fun invoke(scheduler: StageWorkflowService): TaskEligibilityPolicy.Logic = object : TaskEligibilityPolicy.Logic { override fun invoke( task: TaskState ): TaskEligibilityPolicy.Advice = diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/LoadTaskEligibilityPolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/LoadTaskEligibilityPolicy.kt index 090f7be7..a80a8c63 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/LoadTaskEligibilityPolicy.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/LoadTaskEligibilityPolicy.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,16 +20,16 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service.stage.task +package org.opendc.workflows.service.stage.task -import com.atlarge.opendc.workflows.service.StageWorkflowService -import com.atlarge.opendc.workflows.service.TaskState +import org.opendc.workflows.service.StageWorkflowService +import org.opendc.workflows.service.TaskState /** * A [TaskEligibilityPolicy] that limits the number of active tasks in the system based on the average system load. */ -data class LoadTaskEligibilityPolicy(val limit: Double) : TaskEligibilityPolicy { - override fun invoke(scheduler: StageWorkflowService) = object : TaskEligibilityPolicy.Logic { +public data class LoadTaskEligibilityPolicy(val limit: Double) : TaskEligibilityPolicy { + override fun invoke(scheduler: StageWorkflowService): TaskEligibilityPolicy.Logic = object : TaskEligibilityPolicy.Logic { override fun invoke( task: TaskState ): TaskEligibilityPolicy.Advice = diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/NullTaskEligibilityPolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/NullTaskEligibilityPolicy.kt index 889f2ab5..b40f9823 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/NullTaskEligibilityPolicy.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/NullTaskEligibilityPolicy.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,15 +20,15 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service.stage.task +package org.opendc.workflows.service.stage.task -import com.atlarge.opendc.workflows.service.StageWorkflowService -import com.atlarge.opendc.workflows.service.TaskState +import org.opendc.workflows.service.StageWorkflowService +import org.opendc.workflows.service.TaskState /** * A [TaskEligibilityPolicy] that always allows new tasks to enter. */ -object NullTaskEligibilityPolicy : TaskEligibilityPolicy { +public object NullTaskEligibilityPolicy : TaskEligibilityPolicy { override fun invoke(scheduler: StageWorkflowService): TaskEligibilityPolicy.Logic = Logic private object Logic : TaskEligibilityPolicy.Logic { diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/RandomTaskEligibilityPolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/RandomTaskEligibilityPolicy.kt index d6f49d14..a0691b23 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/RandomTaskEligibilityPolicy.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/RandomTaskEligibilityPolicy.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,17 +20,17 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service.stage.task +package org.opendc.workflows.service.stage.task -import com.atlarge.opendc.workflows.service.StageWorkflowService -import com.atlarge.opendc.workflows.service.TaskState -import java.util.Random +import org.opendc.workflows.service.StageWorkflowService +import org.opendc.workflows.service.TaskState +import java.util.* /** * A [TaskEligibilityPolicy] that randomly accepts tasks in the system with some [probability]. */ -data class RandomTaskEligibilityPolicy(val probability: Double = 0.5) : TaskEligibilityPolicy { - override fun invoke(scheduler: StageWorkflowService) = object : TaskEligibilityPolicy.Logic { +public data class RandomTaskEligibilityPolicy(val probability: Double = 0.5) : TaskEligibilityPolicy { + override fun invoke(scheduler: StageWorkflowService): TaskEligibilityPolicy.Logic = object : TaskEligibilityPolicy.Logic { val random = Random(123) override fun invoke(task: TaskState): TaskEligibilityPolicy.Advice = diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/RandomTaskOrderPolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/RandomTaskOrderPolicy.kt index 4c309085..890e7165 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/RandomTaskOrderPolicy.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/RandomTaskOrderPolicy.kt @@ -22,18 +22,18 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service.stage.task +package org.opendc.workflows.service.stage.task -import com.atlarge.opendc.workflows.service.StageWorkflowSchedulerListener -import com.atlarge.opendc.workflows.service.StageWorkflowService -import com.atlarge.opendc.workflows.service.TaskState -import com.atlarge.opendc.workflows.workload.Task +import org.opendc.workflows.service.StageWorkflowSchedulerListener +import org.opendc.workflows.service.StageWorkflowService +import org.opendc.workflows.service.TaskState +import org.opendc.workflows.workload.Task import kotlin.random.Random /** * A [TaskOrderPolicy] that orders the tasks randomly. */ -object RandomTaskOrderPolicy : TaskOrderPolicy { +public object RandomTaskOrderPolicy : TaskOrderPolicy { override fun invoke(scheduler: StageWorkflowService): Comparator<TaskState> = object : Comparator<TaskState>, StageWorkflowSchedulerListener { private val random = Random(123) diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/SubmissionTimeTaskOrderPolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/SubmissionTimeTaskOrderPolicy.kt index a261965f..6b0199b8 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/SubmissionTimeTaskOrderPolicy.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/SubmissionTimeTaskOrderPolicy.kt @@ -22,16 +22,16 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service.stage.task +package org.opendc.workflows.service.stage.task -import com.atlarge.opendc.workflows.service.StageWorkflowService -import com.atlarge.opendc.workflows.service.TaskState +import org.opendc.workflows.service.StageWorkflowService +import org.opendc.workflows.service.TaskState /** * A [TaskOrderPolicy] that orders tasks based on the order of arrival in the queue. */ -data class SubmissionTimeTaskOrderPolicy(val ascending: Boolean = true) : TaskOrderPolicy { - override fun invoke(scheduler: StageWorkflowService) = compareBy<TaskState> { +public data class SubmissionTimeTaskOrderPolicy(public val ascending: Boolean = true) : TaskOrderPolicy { + override fun invoke(scheduler: StageWorkflowService): Comparator<TaskState> = compareBy<TaskState> { it.job.submittedAt.let { if (ascending) it else -it } } diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/TaskEligibilityPolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/TaskEligibilityPolicy.kt index 72a7fdd0..37597709 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/TaskEligibilityPolicy.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/TaskEligibilityPolicy.kt @@ -22,23 +22,23 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service.stage.task +package org.opendc.workflows.service.stage.task -import com.atlarge.opendc.workflows.service.TaskState -import com.atlarge.opendc.workflows.service.stage.StagePolicy +import org.opendc.workflows.service.TaskState +import org.opendc.workflows.service.stage.StagePolicy /** * A policy interface for determining the eligibility of tasks in a scheduling cycle. */ -interface TaskEligibilityPolicy : StagePolicy<TaskEligibilityPolicy.Logic> { - interface Logic { +public interface TaskEligibilityPolicy : StagePolicy<TaskEligibilityPolicy.Logic> { + public interface Logic { /** * Determine whether the specified [TaskState] is eligible to be scheduled. * * @param task The task instance to schedule. * @return The advice for marking the task. */ - operator fun invoke(task: TaskState): Advice + public operator fun invoke(task: TaskState): Advice } /** @@ -48,7 +48,7 @@ interface TaskEligibilityPolicy : StagePolicy<TaskEligibilityPolicy.Logic> { * @property stop A flag to indicate the scheduler should immediately stop admitting jobs to the scheduling queue and wait * for the next scheduling cycle. */ - enum class Advice(val admit: Boolean, val stop: Boolean) { + public enum class Advice(public val admit: Boolean, public val stop: Boolean) { /** * Admit the current job to the scheduling queue and continue admitting jobs. */ diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/TaskOrderPolicy.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/TaskOrderPolicy.kt index e74082c2..5feac6d0 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/stage/task/TaskOrderPolicy.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/service/stage/task/TaskOrderPolicy.kt @@ -22,13 +22,13 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service.stage.task +package org.opendc.workflows.service.stage.task -import com.atlarge.opendc.workflows.service.TaskState -import com.atlarge.opendc.workflows.service.stage.StagePolicy +import org.opendc.workflows.service.TaskState +import org.opendc.workflows.service.stage.StagePolicy /** * This interface represents the **T2** stage of the Reference Architecture for Topology Schedulers and provides the * scheduler with a sorted list of tasks to schedule. */ -interface TaskOrderPolicy : StagePolicy<Comparator<TaskState>> +public interface TaskOrderPolicy : StagePolicy<Comparator<TaskState>> diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/workload/Job.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/workload/Job.kt index 02969d8a..f1cfdf65 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/workload/Job.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/workload/Job.kt @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2019 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,11 +20,11 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.workload +package org.opendc.workflows.workload -import com.atlarge.opendc.core.User -import com.atlarge.opendc.core.workload.Workload -import java.util.UUID +import org.opendc.core.User +import org.opendc.core.workload.Workload +import java.util.* /** * A workload that represents a directed acyclic graph (DAG) of tasks with control and data dependencies between tasks. @@ -37,12 +35,12 @@ import java.util.UUID * @property tasks The tasks that are part of this workflow. * @property metadata Additional metadata for the job. */ -data class Job( +public data class Job( override val uid: UUID, override val name: String, override val owner: User, - val tasks: Set<Task>, - val metadata: Map<String, Any> = emptyMap() + public val tasks: Set<Task>, + public val metadata: Map<String, Any> = emptyMap() ) : Workload { override fun equals(other: Any?): Boolean = other is Job && uid == other.uid diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/workload/Metadata.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/workload/Metadata.kt index 067f1179..d02e2b4e 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/workload/Metadata.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/workload/Metadata.kt @@ -22,9 +22,9 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.workload +package org.opendc.workflows.workload /** * Meta-data key for the deadline of a task. */ -const val WORKFLOW_TASK_DEADLINE = "workflow:task:deadline" +public const val WORKFLOW_TASK_DEADLINE: String = "workflow:task:deadline" diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/workload/Task.kt b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/workload/Task.kt index 82521faa..1834a4c8 100644 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/workload/Task.kt +++ b/simulator/opendc-workflows/src/main/kotlin/org/opendc/workflows/workload/Task.kt @@ -22,11 +22,11 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.workload +package org.opendc.workflows.workload -import com.atlarge.opendc.compute.core.image.Image -import com.atlarge.opendc.core.Identity -import java.util.UUID +import org.opendc.compute.core.image.Image +import org.opendc.core.Identity +import java.util.* /** * A stage of a [Job]. @@ -37,12 +37,12 @@ import java.util.UUID * @property dependencies The dependencies of this task in order for it to execute. * @property metadata Additional metadata for this task. */ -data class Task( +public data class Task( override val uid: UUID, override val name: String, - val image: Image, - val dependencies: Set<Task>, - val metadata: Map<String, Any> = emptyMap() + public val image: Image, + public val dependencies: Set<Task>, + public val metadata: Map<String, Any> = emptyMap() ) : Identity { override fun equals(other: Any?): Boolean = other is Task && uid == other.uid diff --git a/simulator/opendc/opendc-workflows/src/test/kotlin/com/atlarge/opendc/workflows/service/StageWorkflowSchedulerIntegrationTest.kt b/simulator/opendc-workflows/src/test/kotlin/org/opendc/workflows/service/StageWorkflowSchedulerIntegrationTest.kt index 5c129e37..90cf5b99 100644 --- a/simulator/opendc/opendc-workflows/src/test/kotlin/com/atlarge/opendc/workflows/service/StageWorkflowSchedulerIntegrationTest.kt +++ b/simulator/opendc-workflows/src/test/kotlin/org/opendc/workflows/service/StageWorkflowSchedulerIntegrationTest.kt @@ -22,35 +22,36 @@ * SOFTWARE. */ -package com.atlarge.opendc.workflows.service +package org.opendc.workflows.service -import com.atlarge.odcsim.SimulationEngineProvider -import com.atlarge.odcsim.simulationContext -import com.atlarge.opendc.compute.metal.service.ProvisioningService -import com.atlarge.opendc.format.environment.sc18.Sc18EnvironmentReader -import com.atlarge.opendc.format.trace.gwf.GwfTraceReader -import com.atlarge.opendc.workflows.service.stage.job.NullJobAdmissionPolicy -import com.atlarge.opendc.workflows.service.stage.job.SubmissionTimeJobOrderPolicy -import com.atlarge.opendc.workflows.service.stage.resource.FirstFitResourceSelectionPolicy -import com.atlarge.opendc.workflows.service.stage.resource.FunctionalResourceFilterPolicy -import com.atlarge.opendc.workflows.service.stage.task.NullTaskEligibilityPolicy -import com.atlarge.opendc.workflows.service.stage.task.SubmissionTimeTaskOrderPolicy -import java.util.ServiceLoader -import kotlin.math.max +import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.async import kotlinx.coroutines.delay import kotlinx.coroutines.flow.collect import kotlinx.coroutines.flow.onEach import kotlinx.coroutines.launch -import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.TestCoroutineScope 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.core.metal.service.ProvisioningService +import org.opendc.format.environment.sc18.Sc18EnvironmentReader +import org.opendc.format.trace.gwf.GwfTraceReader +import org.opendc.simulator.utils.DelayControllerClockAdapter +import org.opendc.workflows.service.stage.job.NullJobAdmissionPolicy +import org.opendc.workflows.service.stage.job.SubmissionTimeJobOrderPolicy +import org.opendc.workflows.service.stage.resource.FirstFitResourceSelectionPolicy +import org.opendc.workflows.service.stage.resource.FunctionalResourceFilterPolicy +import org.opendc.workflows.service.stage.task.NullTaskEligibilityPolicy +import org.opendc.workflows.service.stage.task.SubmissionTimeTaskOrderPolicy +import kotlin.math.max /** * Integration test suite for the [StageWorkflowService]. */ @DisplayName("StageWorkflowService") +@OptIn(ExperimentalCoroutinesApi::class) internal class StageWorkflowSchedulerIntegrationTest { /** * A large integration test where we check whether all tasks in some trace are executed correctly. @@ -63,16 +64,16 @@ internal class StageWorkflowSchedulerIntegrationTest { var tasksStarted = 0L var tasksFinished = 0L - val provider = ServiceLoader.load(SimulationEngineProvider::class.java).first() - val system = provider(name = "sim") + val testScope = TestCoroutineScope() + val clock = DelayControllerClockAdapter(testScope) - val schedulerDomain = system.newDomain(name = "scheduler") - val schedulerAsync = schedulerDomain.async { + val schedulerAsync = testScope.async { val environment = Sc18EnvironmentReader(object {}.javaClass.getResourceAsStream("/environment.json")) - .use { it.construct(system.newDomain("topology")) } + .use { it.construct(testScope, clock) } StageWorkflowService( - schedulerDomain, + testScope, + clock, environment.platforms[0].zones[0].services[ProvisioningService], mode = WorkflowSchedulerMode.Batch(100), jobAdmissionPolicy = NullJobAdmissionPolicy, @@ -84,9 +85,7 @@ internal class StageWorkflowSchedulerIntegrationTest { ) } - val broker = system.newDomain(name = "broker") - - broker.launch { + testScope.launch { val scheduler = schedulerAsync.await() scheduler.events .onEach { event -> @@ -100,24 +99,21 @@ internal class StageWorkflowSchedulerIntegrationTest { .collect() } - broker.launch { - val ctx = simulationContext + testScope.launch { val reader = GwfTraceReader(object {}.javaClass.getResourceAsStream("/trace.gwf")) val scheduler = schedulerAsync.await() while (reader.hasNext()) { val (time, job) = reader.next() jobsSubmitted++ - delay(max(0, time * 1000 - ctx.clock.millis())) + delay(max(0, time * 1000 - clock.millis())) scheduler.submit(job) } } - runBlocking { - system.run() - system.terminate() - } + testScope.advanceUntilIdle() + assertNotEquals(0, jobsSubmitted, "No jobs submitted") assertEquals(jobsSubmitted, jobsStarted, "Not all submitted jobs started") assertEquals(jobsSubmitted, jobsFinished, "Not all started jobs finished") assertEquals(tasksStarted, tasksFinished, "Not all started tasks finished") diff --git a/simulator/opendc/opendc-workflows/src/test/resources/environment.json b/simulator/opendc-workflows/src/test/resources/environment.json index 0965b250..0965b250 100644 --- a/simulator/opendc/opendc-workflows/src/test/resources/environment.json +++ b/simulator/opendc-workflows/src/test/resources/environment.json diff --git a/simulator/opendc/opendc-workflows/src/test/resources/trace.gwf b/simulator/opendc-workflows/src/test/resources/trace.gwf index d264b9c3..d264b9c3 100644 --- a/simulator/opendc/opendc-workflows/src/test/resources/trace.gwf +++ b/simulator/opendc-workflows/src/test/resources/trace.gwf diff --git a/simulator/opendc/README.md b/simulator/opendc/README.md deleted file mode 100644 index e3c65ba7..00000000 --- a/simulator/opendc/README.md +++ /dev/null @@ -1,8 +0,0 @@ -<h1 align="center"> - <a href="http://opendc.org/"> - <img src="../misc/artwork/logo.png" width="100" alt="OpenDC"> - </a> - <br> - OpenDC -</h1> - diff --git a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/execution/ShutdownException.kt b/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/execution/ShutdownException.kt deleted file mode 100644 index e4da557b..00000000 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/execution/ShutdownException.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * MIT License - * - * 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 com.atlarge.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/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/image/FlopsHistoryFragment.kt b/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/image/FlopsHistoryFragment.kt deleted file mode 100644 index 5b0035e3..00000000 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/image/FlopsHistoryFragment.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.atlarge.opendc.compute.core.image - -data class FlopsHistoryFragment(val tick: Long, val flops: Long, val duration: Long, val usage: Double, val cores: Int) diff --git a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/image/VmImage.kt b/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/image/VmImage.kt deleted file mode 100644 index c615d865..00000000 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/image/VmImage.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.atlarge.opendc.compute.core.image - -import com.atlarge.odcsim.simulationContext -import com.atlarge.opendc.compute.core.execution.ServerContext -import com.atlarge.opendc.core.resource.TagContainer -import java.util.UUID -import kotlin.math.min - -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) { - val clock = simulationContext.clock - var offset = clock.millis() - - val batch = flopsHistory.map { fragment -> - val cores = min(fragment.cores, ctx.server.flavor.cpuCount) - val burst = LongArray(cores) { fragment.flops / cores } - val usage = DoubleArray(cores) { fragment.usage / cores } - offset += fragment.duration - ServerContext.Slice(burst, usage, offset) - } - - ctx.run(batch) - } - - override fun toString(): String = "VmImage(uid=$uid, name=$name, cores=$maxCores, requiredMemory=$requiredMemory)" -} diff --git a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/workload/PerformanceInterferenceModel.kt b/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/workload/PerformanceInterferenceModel.kt deleted file mode 100644 index 3f885f89..00000000 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/workload/PerformanceInterferenceModel.kt +++ /dev/null @@ -1,123 +0,0 @@ -/* - * MIT License - * - * 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 com.atlarge.opendc.compute.core.workload - -import com.atlarge.opendc.compute.core.Server -import java.util.* -import kotlin.random.Random - -/** - * Meta-data key for the [PerformanceInterferenceModel] of an image. - */ -const val IMAGE_PERF_INTERFERENCE_MODEL = "image:performance-interference" - -/** - * Performance Interference Model describing the variability incurred by different sets of workloads if colocated. - * - * @param items The [PerformanceInterferenceModelItem]s that make up this model. - */ -class PerformanceInterferenceModel( - val items: SortedSet<PerformanceInterferenceModelItem>, - val random: Random = Random(0) -) { - private var intersectingItems: List<PerformanceInterferenceModelItem> = emptyList() - private val colocatedWorkloads = TreeMap<String, Int>() - - fun vmStarted(server: Server) { - colocatedWorkloads.merge(server.image.name, 1, Int::plus) - intersectingItems = items.filter { item -> doesMatch(item) } - } - - fun vmStopped(server: Server) { - colocatedWorkloads.computeIfPresent(server.image.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 - } - - fun apply(currentServerLoad: Double): Double { - if (intersectingItems.isEmpty()) { - return 1.0 - } - val score = intersectingItems - .firstOrNull { it.minServerLoad <= currentServerLoad } - - // Apply performance penalty to (on average) only one of the VMs - return if (score != null && random.nextInt(score.workloadNames.size) == 0) { - score.performanceScore - } else { - 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. - */ -data class PerformanceInterferenceModelItem( - val workloadNames: SortedSet<String>, - val minServerLoad: Double, - 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 - - if (workloadNames != other.workloadNames) return false - - return true - } - - override fun hashCode(): Int = workloadNames.hashCode() - - 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 - } - - return hashCode().compareTo(other.hashCode()) - } -} diff --git a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/workload/VmWorkload.kt b/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/workload/VmWorkload.kt deleted file mode 100644 index 098eb8ca..00000000 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/core/workload/VmWorkload.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.atlarge.opendc.compute.core.workload - -import com.atlarge.opendc.compute.core.image.VmImage -import com.atlarge.opendc.core.User -import com.atlarge.opendc.core.workload.Workload -import java.util.UUID - -/** - * A workload that represents a VM. - * - * @property uid A unique identified of this VM. - * @property name The name of this VM. - * @property owner The owner of the VM. - * @property image The image of the VM. - */ -data class VmWorkload( - override val uid: UUID, - override val name: String, - override val owner: User, - val image: VmImage -) : Workload { - override fun equals(other: Any?): Boolean = other is VmWorkload && uid == other.uid - - override fun hashCode(): Int = uid.hashCode() -} diff --git a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/metal/driver/SimpleBareMetalDriver.kt b/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/metal/driver/SimpleBareMetalDriver.kt deleted file mode 100644 index a453e459..00000000 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/metal/driver/SimpleBareMetalDriver.kt +++ /dev/null @@ -1,478 +0,0 @@ -/* - * MIT License - * - * 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 com.atlarge.opendc.compute.metal.driver - -import com.atlarge.odcsim.Domain -import com.atlarge.odcsim.SimulationContext -import com.atlarge.odcsim.flow.EventFlow -import com.atlarge.odcsim.flow.StateFlow -import com.atlarge.opendc.compute.core.Flavor -import com.atlarge.opendc.compute.core.MemoryUnit -import com.atlarge.opendc.compute.core.ProcessingUnit -import com.atlarge.opendc.compute.core.Server -import com.atlarge.opendc.compute.core.ServerEvent -import com.atlarge.opendc.compute.core.ServerState -import com.atlarge.opendc.compute.core.execution.ServerContext -import com.atlarge.opendc.compute.core.execution.ServerManagementContext -import com.atlarge.opendc.compute.core.execution.ShutdownException -import com.atlarge.opendc.compute.core.image.EmptyImage -import com.atlarge.opendc.compute.core.image.Image -import com.atlarge.opendc.compute.metal.Node -import com.atlarge.opendc.compute.metal.NodeEvent -import com.atlarge.opendc.compute.metal.NodeState -import com.atlarge.opendc.compute.metal.power.ConstantPowerModel -import com.atlarge.opendc.core.power.PowerModel -import com.atlarge.opendc.core.services.ServiceKey -import com.atlarge.opendc.core.services.ServiceRegistry -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 -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 kotlinx.coroutines.withContext - -/** - * A basic implementation of the [BareMetalDriver] that simulates an [Image] running on a bare-metal machine. - * - * @param domain The simulation domain the driver runs in. - * @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 domain: Domain, - uid: UUID, - name: String, - metadata: Map<String, Any>, - val cpus: List<ProcessingUnit>, - 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 = withContext(domain.coroutineContext) { - nodeState.value - } - - override suspend fun start(): Node = withContext(domain.coroutineContext) { - val node = nodeState.value - if (node.state != NodeState.SHUTOFF) { - return@withContext 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@withContext nodeState.value - } - - override suspend fun stop(): Node = withContext(domain.coroutineContext) { - val node = nodeState.value - if (node.state == NodeState.SHUTOFF) { - return@withContext node - } - - // We terminate the image running on the machine - serverContext!!.cancel(fail = false) - serverContext = null - - setNode(node.copy(state = NodeState.SHUTOFF, server = null)) - return@withContext node - } - - override suspend fun reboot(): Node = withContext(domain.coroutineContext) { - stop() - start() - } - - override suspend fun setImage(image: Image): Node = withContext(domain.coroutineContext) { - setNode(nodeState.value.copy(image = image)) - return@withContext nodeState.value - } - - override suspend fun refresh(): Node = withContext(domain.coroutineContext) { 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!! - - private val job = domain.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 [Clock] for timing. - */ - private val clock = domain.coroutineContext[SimulationContext]!!.clock - - /** - * 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 = domain.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, Runnable { - 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() = domain - - 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/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/HypervisorImage.kt b/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/HypervisorImage.kt deleted file mode 100644 index 607759a8..00000000 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/HypervisorImage.kt +++ /dev/null @@ -1,57 +0,0 @@ -/* - * MIT License - * - * 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 com.atlarge.opendc.compute.virt - -import com.atlarge.opendc.compute.core.execution.ServerContext -import com.atlarge.opendc.compute.core.image.Image -import com.atlarge.opendc.compute.virt.driver.SimpleVirtDriver -import com.atlarge.opendc.compute.virt.driver.VirtDriver -import com.atlarge.opendc.core.resource.TagContainer -import java.util.UUID -import kotlinx.coroutines.coroutineScope -import kotlinx.coroutines.suspendCancellableCoroutine - -/** - * A hypervisor managing the VMs of a node. - */ -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/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/HypervisorView.kt b/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/HypervisorView.kt deleted file mode 100644 index e52a1698..00000000 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/HypervisorView.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.atlarge.opendc.compute.virt.service - -import com.atlarge.opendc.compute.core.Server -import com.atlarge.opendc.compute.virt.driver.VirtDriver -import java.util.UUID - -class HypervisorView( - val uid: UUID, - var server: Server, - var numberOfActiveServers: Int, - var availableMemory: Long, - var provisionedCores: Int -) { - lateinit var driver: VirtDriver -} diff --git a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/SimpleVirtProvisioningService.kt b/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/SimpleVirtProvisioningService.kt deleted file mode 100644 index 79388bc3..00000000 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/SimpleVirtProvisioningService.kt +++ /dev/null @@ -1,351 +0,0 @@ -package com.atlarge.opendc.compute.virt.service - -import com.atlarge.odcsim.SimulationContext -import com.atlarge.odcsim.flow.EventFlow -import com.atlarge.odcsim.simulationContext -import com.atlarge.opendc.compute.core.Flavor -import com.atlarge.opendc.compute.core.Server -import com.atlarge.opendc.compute.core.ServerEvent -import com.atlarge.opendc.compute.core.ServerState -import com.atlarge.opendc.compute.core.image.Image -import com.atlarge.opendc.compute.core.image.VmImage -import com.atlarge.opendc.compute.metal.service.ProvisioningService -import com.atlarge.opendc.compute.virt.HypervisorEvent -import com.atlarge.opendc.compute.virt.HypervisorImage -import com.atlarge.opendc.compute.virt.driver.InsufficientMemoryOnServerException -import com.atlarge.opendc.compute.virt.driver.VirtDriver -import com.atlarge.opendc.compute.virt.service.allocation.AllocationPolicy -import com.atlarge.opendc.core.services.ServiceKey -import kotlin.coroutines.Continuation -import kotlin.coroutines.resume -import kotlin.math.max -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.ExperimentalCoroutinesApi -import kotlinx.coroutines.Job -import kotlinx.coroutines.delay -import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.flow.launchIn -import kotlinx.coroutines.flow.onEach -import kotlinx.coroutines.launch -import kotlinx.coroutines.suspendCancellableCoroutine -import kotlinx.coroutines.withContext -import mu.KotlinLogging - -private val logger = KotlinLogging.logger {} - -@OptIn(ExperimentalCoroutinesApi::class) -class SimpleVirtProvisioningService( - public override val allocationPolicy: AllocationPolicy, - private val ctx: SimulationContext, - private val provisioningService: ProvisioningService -) : VirtProvisioningService, CoroutineScope by ctx.domain { - /** - * The hypervisors that have been launched by the service. - */ - private val hypervisors: MutableMap<Server, HypervisorView> = mutableMapOf() - - /** - * The available hypervisors. - */ - private val availableHypervisors: MutableSet<HypervisorView> = mutableSetOf() - - /** - * The incoming images to be processed by the provisioner. - */ - private val incomingImages: MutableSet<ImageView> = mutableSetOf() - - /** - * The active images in the system. - */ - private val activeImages: MutableSet<ImageView> = mutableSetOf() - - public var submittedVms = 0 - public var queuedVms = 0 - public var runningVms = 0 - public var finishedVms = 0 - public var unscheduledVms = 0 - - private var maxCores = 0 - private var maxMemory = 0L - - /** - * The allocation logic to use. - */ - private val allocationLogic = allocationPolicy() - - /** - * The [EventFlow] to emit the events. - */ - internal val eventFlow = EventFlow<VirtProvisioningEvent>() - - override val events: Flow<VirtProvisioningEvent> = eventFlow - - init { - 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) - } - } - } - - override suspend fun drivers(): Set<VirtDriver> = withContext(coroutineContext) { - availableHypervisors.map { it.driver }.toSet() - } - - override suspend fun deploy( - name: String, - image: Image, - flavor: Flavor - ): Server = withContext(coroutineContext) { - eventFlow.emit(VirtProvisioningEvent.MetricsAvailable( - this@SimpleVirtProvisioningService, - hypervisors.size, - availableHypervisors.size, - ++submittedVms, - runningVms, - finishedVms, - ++queuedVms, - unscheduledVms - )) - - suspendCancellableCoroutine<Server> { cont -> - val vmInstance = ImageView(name, image, flavor, cont) - incomingImages += vmInstance - requestCycle() - } - } - - override suspend fun terminate() { - val provisionedNodes = provisioningService.nodes() - provisionedNodes.forEach { node -> provisioningService.stop(node) } - } - - private var call: Job? = null - - private fun requestCycle() { - if (call != null) { - return - } - - val quantum = 300000 // 5 minutes in milliseconds - // We assume that the provisioner runs at a fixed slot every time quantum (e.g t=0, t=60, t=120). - // This is important because the slices of the VMs need to be aligned. - // We calculate here the delay until the next scheduling slot. - val delay = quantum - (ctx.clock.millis() % quantum) - - val call = launch { - delay(delay) - this@SimpleVirtProvisioningService.call = null - schedule() - } - this.call = call - } - - private suspend fun schedule() { - val clock = simulationContext.clock - val imagesToBeScheduled = incomingImages.toSet() - - for (imageInstance in imagesToBeScheduled) { - val requiredMemory = (imageInstance.image as VmImage).requiredMemory - val selectedHv = allocationLogic.select(availableHypervisors, imageInstance) - - if (selectedHv == null) { - if (requiredMemory > maxMemory || imageInstance.flavor.cpuCount > maxCores) { - eventFlow.emit(VirtProvisioningEvent.MetricsAvailable( - this@SimpleVirtProvisioningService, - hypervisors.size, - availableHypervisors.size, - submittedVms, - runningVms, - finishedVms, - queuedVms, - ++unscheduledVms - )) - - incomingImages -= imageInstance - - logger.warn("Failed to spawn ${imageInstance.image}: does not fit [${clock.millis()}]") - continue - } else { - break - } - } - - try { - logger.info { "[${ctx.clock.millis()}] Spawning ${imageInstance.image} on ${selectedHv.server.uid} ${selectedHv.server.name} ${selectedHv.server.flavor}" } - incomingImages -= imageInstance - - // Speculatively update the hypervisor view information to prevent other images in the queue from - // deciding on stale values. - selectedHv.numberOfActiveServers++ - selectedHv.provisionedCores += imageInstance.flavor.cpuCount - selectedHv.availableMemory -= requiredMemory // XXX Temporary hack - - val server = selectedHv.driver.spawn( - imageInstance.name, - imageInstance.image, - imageInstance.flavor - ) - imageInstance.server = server - imageInstance.continuation.resume(server) - - eventFlow.emit(VirtProvisioningEvent.MetricsAvailable( - this@SimpleVirtProvisioningService, - hypervisors.size, - availableHypervisors.size, - submittedVms, - ++runningVms, - finishedVms, - --queuedVms, - unscheduledVms - )) - activeImages += imageInstance - - server.events - .onEach { event -> - when (event) { - is ServerEvent.StateChanged -> { - if (event.server.state == ServerState.SHUTOFF) { - logger.info { "[${ctx.clock.millis()}] Server ${event.server.uid} ${event.server.name} ${event.server.flavor} finished." } - - eventFlow.emit(VirtProvisioningEvent.MetricsAvailable( - this@SimpleVirtProvisioningService, - hypervisors.size, - availableHypervisors.size, - submittedVms, - --runningVms, - ++finishedVms, - queuedVms, - unscheduledVms - )) - - activeImages -= imageInstance - selectedHv.provisionedCores -= server.flavor.cpuCount - - // Try to reschedule if needed - if (incomingImages.isNotEmpty()) { - requestCycle() - } - } - } - } - } - .launchIn(this) - } catch (e: InsufficientMemoryOnServerException) { - logger.error("Failed to deploy VM", e) - - selectedHv.numberOfActiveServers-- - selectedHv.provisionedCores -= imageInstance.flavor.cpuCount - selectedHv.availableMemory += requiredMemory - } catch (e: Throwable) { - logger.error("Failed to deploy VM", e) - } - } - } - - private fun stateChanged(server: Server) { - when (server.state) { - ServerState.ACTIVE -> { - logger.debug { "[${ctx.clock.millis()}] Server ${server.uid} available: ${server.state}" } - - if (server in hypervisors) { - // Corner case for when the hypervisor already exists - availableHypervisors += hypervisors.getValue(server) - } else { - val hv = HypervisorView( - server.uid, - server, - 0, - server.flavor.memorySize, - 0 - ) - maxCores = max(maxCores, server.flavor.cpuCount) - maxMemory = max(maxMemory, server.flavor.memorySize) - hypervisors[server] = hv - } - - eventFlow.emit(VirtProvisioningEvent.MetricsAvailable( - this@SimpleVirtProvisioningService, - hypervisors.size, - availableHypervisors.size, - submittedVms, - runningVms, - finishedVms, - queuedVms, - unscheduledVms - )) - - // Re-schedule on the new machine - if (incomingImages.isNotEmpty()) { - requestCycle() - } - } - ServerState.SHUTOFF, ServerState.ERROR -> { - logger.debug { "[${ctx.clock.millis()}] Server ${server.uid} unavailable: ${server.state}" } - val hv = hypervisors[server] ?: return - availableHypervisors -= hv - - eventFlow.emit(VirtProvisioningEvent.MetricsAvailable( - this@SimpleVirtProvisioningService, - hypervisors.size, - availableHypervisors.size, - submittedVms, - runningVms, - finishedVms, - queuedVms, - unscheduledVms - )) - - if (incomingImages.isNotEmpty()) { - requestCycle() - } - } - else -> throw IllegalStateException() - } - } - - 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 - )) - - hv.driver.events - .onEach { event -> - if (event is HypervisorEvent.VmsUpdated) { - hv.numberOfActiveServers = event.numberOfActiveServers - hv.availableMemory = event.availableMemory - } - }.launchIn(this) - - requestCycle() - } - } - - data class ImageView( - val name: String, - val image: Image, - val flavor: Flavor, - val continuation: Continuation<Server>, - var server: Server? = null - ) -} diff --git a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/VirtProvisioningService.kt b/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/VirtProvisioningService.kt deleted file mode 100644 index c4cbd711..00000000 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/VirtProvisioningService.kt +++ /dev/null @@ -1,42 +0,0 @@ -package com.atlarge.opendc.compute.virt.service - -import com.atlarge.opendc.compute.core.Flavor -import com.atlarge.opendc.compute.core.Server -import com.atlarge.opendc.compute.core.image.Image -import com.atlarge.opendc.compute.virt.driver.VirtDriver -import com.atlarge.opendc.compute.virt.service.allocation.AllocationPolicy -import kotlinx.coroutines.flow.Flow - -/** - * A service for VM provisioning on a cloud. - */ -interface VirtProvisioningService { - /** - * The policy used for allocating a VM on the available hypervisors. - */ - val allocationPolicy: AllocationPolicy - - /** - * The events emitted by the service. - */ - public val events: Flow<VirtProvisioningEvent> - - /** - * Obtain the active hypervisors for this provisioner. - */ - public suspend fun drivers(): Set<VirtDriver> - - /** - * Submit the specified [Image] to the provisioning service. - * - * @param name The name of the server to deploy. - * @param image The image to be deployed. - * @param flavor The flavor of the machine instance to run this [image] on. - */ - public suspend fun deploy(name: String, image: Image, flavor: Flavor): Server - - /** - * Terminate the provisioning service releasing all the leased bare-metal machines. - */ - public suspend fun terminate() -} diff --git a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/allocation/AllocationPolicy.kt b/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/allocation/AllocationPolicy.kt deleted file mode 100644 index b7c9388d..00000000 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/allocation/AllocationPolicy.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.atlarge.opendc.compute.virt.service.allocation - -import com.atlarge.opendc.compute.metal.Node -import com.atlarge.opendc.compute.virt.service.HypervisorView -import com.atlarge.opendc.compute.virt.service.SimpleVirtProvisioningService - -/** - * A policy for selecting the [Node] an image should be deployed to, - */ -public interface AllocationPolicy { - /** - * The logic of the allocation policy. - */ - public interface Logic { - /** - * Select the node on which the server should be scheduled. - */ - public fun select(hypervisors: Set<HypervisorView>, image: SimpleVirtProvisioningService.ImageView): HypervisorView? - } - - /** - * Builds the logic of the policy. - */ - operator fun invoke(): Logic -} diff --git a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/allocation/AvailableMemoryAllocationPolicy.kt b/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/allocation/AvailableMemoryAllocationPolicy.kt deleted file mode 100644 index c081244f..00000000 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/allocation/AvailableMemoryAllocationPolicy.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.atlarge.opendc.compute.virt.service.allocation - -import com.atlarge.opendc.compute.virt.service.HypervisorView - -/** - * Allocation policy that selects the node with the most available memory. - * - * @param reversed A flag to reverse the order (least amount of memory scores the best). - */ -public class AvailableMemoryAllocationPolicy(val reversed: Boolean = false) : AllocationPolicy { - override fun invoke(): AllocationPolicy.Logic = object : ComparableAllocationPolicyLogic { - override val comparator: Comparator<HypervisorView> = compareBy<HypervisorView> { -it.availableMemory } - .run { if (reversed) reversed() else this } - } -} diff --git a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/allocation/NumberOfActiveServersAllocationPolicy.kt b/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/allocation/NumberOfActiveServersAllocationPolicy.kt deleted file mode 100644 index 7e3e5864..00000000 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/allocation/NumberOfActiveServersAllocationPolicy.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.atlarge.opendc.compute.virt.service.allocation - -import com.atlarge.opendc.compute.virt.service.HypervisorView - -/** - * Allocation policy that selects the node with the least amount of active servers. - * - * @param reversed A flag to reverse the order, such that the node with the most active servers is selected. - */ -public class NumberOfActiveServersAllocationPolicy(val reversed: Boolean = false) : AllocationPolicy { - override fun invoke(): AllocationPolicy.Logic = object : ComparableAllocationPolicyLogic { - override val comparator: Comparator<HypervisorView> = compareBy<HypervisorView> { it.numberOfActiveServers } - .run { if (reversed) reversed() else this } - } -} diff --git a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/allocation/ReplayAllocationPolicy.kt b/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/allocation/ReplayAllocationPolicy.kt deleted file mode 100644 index 59acfce2..00000000 --- a/simulator/opendc/opendc-compute/src/main/kotlin/com/atlarge/opendc/compute/virt/service/allocation/ReplayAllocationPolicy.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.atlarge.opendc.compute.virt.service.allocation - -import com.atlarge.opendc.compute.virt.service.HypervisorView -import com.atlarge.opendc.compute.virt.service.SimpleVirtProvisioningService -import mu.KotlinLogging - -private val logger = KotlinLogging.logger {} - -/** - * Policy replaying VM-cluster assignment. - * - * Within each cluster, the active servers on each node determine which node gets - * assigned the VM image. - */ -class ReplayAllocationPolicy(val vmPlacements: Map<String, String>) : AllocationPolicy { - override fun invoke(): AllocationPolicy.Logic = object : AllocationPolicy.Logic { - override fun select( - hypervisors: Set<HypervisorView>, - image: SimpleVirtProvisioningService.ImageView - ): HypervisorView? { - val clusterName = vmPlacements[image.name] - ?: throw IllegalStateException("Could not find placement data in VM placement file for VM ${image.name}") - val machinesInCluster = hypervisors.filter { it.server.name.contains(clusterName) } - - 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 machinesInCluster.maxBy { it.availableMemory } - ?: throw IllegalStateException("Cloud not find any machine and could not randomly assign") - } - } -} diff --git a/simulator/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/virt/HypervisorTest.kt b/simulator/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/virt/HypervisorTest.kt deleted file mode 100644 index 622b185e..00000000 --- a/simulator/opendc/opendc-compute/src/test/kotlin/com/atlarge/opendc/compute/virt/HypervisorTest.kt +++ /dev/null @@ -1,167 +0,0 @@ -/* - * MIT License - * - * 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 com.atlarge.opendc.compute.virt - -import com.atlarge.odcsim.SimulationEngineProvider -import com.atlarge.opendc.compute.core.Flavor -import com.atlarge.opendc.compute.core.ProcessingNode -import com.atlarge.opendc.compute.core.ProcessingUnit -import com.atlarge.opendc.compute.core.image.FlopsApplicationImage -import com.atlarge.opendc.compute.core.image.FlopsHistoryFragment -import com.atlarge.opendc.compute.core.image.VmImage -import com.atlarge.opendc.compute.metal.driver.SimpleBareMetalDriver -import com.atlarge.opendc.compute.virt.driver.VirtDriver -import java.util.ServiceLoader -import java.util.UUID -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.runBlocking -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 - -/** - * Basic test-suite for the hypervisor. - */ -internal class HypervisorTest { - /** - * A smoke test for the bare-metal driver. - */ - @OptIn(ExperimentalCoroutinesApi::class) - @Test - @Disabled - fun smoke() { - val provider = ServiceLoader.load(SimulationEngineProvider::class.java).first() - val system = provider("test") - val root = system.newDomain("root") - - root.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 driverDom = root.newDomain("driver") - - val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 1) - val cpus = List(1) { ProcessingUnit(cpuNode, it, 2000.0) } - val metalDriver = SimpleBareMetalDriver(driverDom, 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) - } - - runBlocking { - system.run() - system.terminate() - } - } - - /** - * Test overcommissioning of a hypervisor. - */ - @Test - fun overcommission() { - val provider = ServiceLoader.load(SimulationEngineProvider::class.java).first() - val system = provider("test") - val root = system.newDomain("root") - - var requestedBurst = 0L - var grantedBurst = 0L - var overcommissionedBurst = 0L - - root.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 driverDom = root.newDomain("driver") - - val cpuNode = ProcessingNode("Intel", "Xeon", "amd64", 2) - val cpus = List(2) { ProcessingUnit(cpuNode, it, 3200.0) } - val metalDriver = SimpleBareMetalDriver(driverDom, 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) - } - - runBlocking { - system.run() - system.terminate() - } - - 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/opendc-format/src/test/kotlin/com/atlarge/opendc/format/trace/swf/SwfTraceReaderTest.kt b/simulator/opendc/opendc-format/src/test/kotlin/com/atlarge/opendc/format/trace/swf/SwfTraceReaderTest.kt deleted file mode 100644 index 94e4b0fc..00000000 --- a/simulator/opendc/opendc-format/src/test/kotlin/com/atlarge/opendc/format/trace/swf/SwfTraceReaderTest.kt +++ /dev/null @@ -1,23 +0,0 @@ -package com.atlarge.opendc.format.trace.swf - -import java.io.File -import org.junit.jupiter.api.Assertions.assertEquals -import org.junit.jupiter.api.Test - -class SwfTraceReaderTest { - @Test - internal fun testParseSwf() { - val reader = SwfTraceReader(File(SwfTraceReaderTest::class.java.getResource("/swf_trace.txt").toURI())) - 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) - - 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) - } -} diff --git a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/StageWorkflowSchedulerListener.kt b/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/StageWorkflowSchedulerListener.kt deleted file mode 100644 index 73c3e752..00000000 --- a/simulator/opendc/opendc-workflows/src/main/kotlin/com/atlarge/opendc/workflows/service/StageWorkflowSchedulerListener.kt +++ /dev/null @@ -1,39 +0,0 @@ -/* - * MIT License - * - * 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 com.atlarge.opendc.workflows.service - -interface StageWorkflowSchedulerListener { - fun cycleStarted(scheduler: StageWorkflowService) {} - fun cycleFinished(scheduler: StageWorkflowService) {} - - fun jobSubmitted(job: JobState) {} - fun jobStarted(job: JobState) {} - fun jobFinished(job: JobState) {} - - fun taskReady(task: TaskState) {} - fun taskAssigned(task: TaskState) {} - fun taskStarted(task: TaskState) {} - fun taskFinished(task: TaskState) {} -} diff --git a/simulator/settings.gradle.kts b/simulator/settings.gradle.kts index 9411d882..935a18d0 100644 --- a/simulator/settings.gradle.kts +++ b/simulator/settings.gradle.kts @@ -1,7 +1,5 @@ /* - * MIT License - * - * Copyright (c) 2017 atlarge-research + * Copyright (c) 2017 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 @@ -23,12 +21,15 @@ */ rootProject.name = "opendc-simulator" -include(":odcsim:odcsim-api") -include(":odcsim:odcsim-engine-omega") -include(":opendc:opendc-core") -include(":opendc:opendc-compute") -include(":opendc:opendc-format") -include(":opendc:opendc-workflows") -include(":opendc:opendc-experiments-sc18") -include(":opendc:opendc-experiments-sc20") -include(":opendc:opendc-runner-web") +include(":opendc-core") +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:opendc-simulator-core") +include(":opendc-simulator:opendc-simulator-compute") +include(":opendc-simulator:opendc-simulator-failures") +include(":opendc-utils") |
