summaryrefslogtreecommitdiff
path: root/opendc-simulator
diff options
context:
space:
mode:
authorDante Niewenhuis <d.niewenhuis@hotmail.com>2024-10-25 13:32:41 +0200
committerGitHub <noreply@github.com>2024-10-25 13:32:41 +0200
commit5a365dbc068f2a8cdfa9813c39cc84bb30e15637 (patch)
tree72716d562787b85e03cdc7fe1d30c827054d25a0 /opendc-simulator
parent27f5b7dcb05aefdab9b762175d538931face0aba (diff)
Rewrote the FlowEngine (#256)
* Removed unused components. Updated tests. Improved checkpointing model Improved model, started with SimPowerSource implemented FailureModels and Checkpointing First working version midway commit first update All simulation are now run with a single CPU and single MemoryUnit. multi CPUs are combined into one. This is for performance and explainability. * fixed merge conflicts * Updated M3SA paths. * Fixed small typo
Diffstat (limited to 'opendc-simulator')
-rw-r--r--opendc-simulator/opendc-simulator-compute/build.gradle.kts2
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/jmh/kotlin/org/opendc/simulator/compute/SimMachineBenchmarks.kt15
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimAbstractMachine.java354
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimBareMetalMachine.java280
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimMachine.java61
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimMachineContext.java96
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimMemory.java41
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimNetworkInterface.java51
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimProcessingUnit.java62
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimPsu.java71
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimPsuFactories.java214
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimPsuFactory.java38
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimStorageInterface.java50
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/cpu/CPUPowerModelsFactory.kt (renamed from opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/CPUPowerModelsFactory.kt)2
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/cpu/CpuPowerModel.java (renamed from opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/CpuPowerModel.java)4
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/cpu/CpuPowerModels.java (renamed from opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/CpuPowerModels.java)2
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/cpu/SimCpu.java260
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/device/SimNetworkAdapter.java36
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/device/SimPeripheral.java33
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/SimHypervisor.java933
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/SimHypervisorCounters.java53
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/cpufreq/ScalingGovernor.java46
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/cpufreq/ScalingGovernorFactory.java33
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/cpufreq/ScalingGovernors.java190
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/cpufreq/ScalingPolicy.java56
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/interference/VmInterferenceDomain.java136
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/interference/VmInterferenceMember.java177
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/interference/VmInterferenceModel.java185
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/interference/VmInterferenceProfile.java60
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/machine/PerformanceCounters.java102
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/machine/SimMachine.java184
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/machine/VirtualMachine.java246
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/memory/Memory.java (renamed from opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PerformanceScalingGovernorTest.kt)43
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/NetworkAdapter.java88
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/ProcessingNode.java100
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/StorageDevice.java112
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/models/CpuModel.java (renamed from opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/Cpu.java)20
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/models/MachineModel.java (renamed from opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/MachineModel.java)67
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/models/MemoryUnit.java (renamed from opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/MemoryUnit.java)4
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/SimPowerSource.java169
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/SimPsu.java196
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/ChainWorkload.java72
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/CheckpointModel.java94
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimChainWorkload.java423
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimFlopsWorkload.java179
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimRuntimeWorkload.java227
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimTrace.java413
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimTraceWorkload.java270
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimWorkload.java32
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimWorkloads.java82
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/TraceFragment.java (renamed from opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimTraceFragment.java)4
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/TraceWorkload.java154
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/Workload.java (renamed from opendc-simulator/opendc-simulator-power/build.gradle.kts)20
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/Coroutines.kt11
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimMachineTest.kt883
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisorTest.kt269
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimSpaceSharedHypervisorTest.kt234
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ConservativeScalingGovernorTest.kt94
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/OnDemandScalingGovernorTest.kt78
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PowerSaveScalingGovernorTest.kt72
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/power/PowerModelTest.kt180
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimChainWorkloadTest.kt310
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimFlopsWorkloadTest.kt59
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkloadTest.kt160
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/jmh/kotlin/org/opendc/simulator/flow2/FlowBenchmarks.kt8
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/Multiplexer.java210
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/FlowConsumer.java (renamed from opendc-simulator/opendc-simulator-network/build.gradle.kts)18
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/FlowEdge.java114
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/FlowEngine.java (renamed from opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/FlowEngine.java)88
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/FlowGraph.java112
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/FlowNode.java191
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/FlowNodeQueue.java (renamed from opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/FlowStageQueue.java)26
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/FlowSupplier.java (renamed from opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/Outlet.java)26
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/FlowTimerQueue.java (renamed from opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/FlowTimerQueue.java)77
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/InvocationStack.java (renamed from opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/InvocationStack.java)21
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/FlowGraph.java63
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/FlowGraphInternal.java93
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/FlowStage.java312
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/FlowStageLogic.java38
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/InHandler.java54
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/InHandlers.java53
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/InPort.java214
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/Inlet.java38
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/OutHandler.java47
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/OutHandlers.java53
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/OutPort.java224
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/mux/FlowMultiplexer.java95
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/mux/FlowMultiplexerFactory.java51
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/mux/ForwardingFlowMultiplexer.java287
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/mux/MaxMinFlowMultiplexer.java297
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/sink/FlowSink.java36
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/sink/SimpleFlowSink.java123
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/source/EmptyFlowSource.java65
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/source/FlowSource.java36
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/source/RuntimeFlowSource.java128
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/source/SimpleFlowSource.java131
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/source/TraceFlowSource.java151
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/util/FlowTransform.java41
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/util/FlowTransformer.java124
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/util/FlowTransforms.java57
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/test/kotlin/InvocationStackTest.kt (renamed from opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/InvocationStackTest.kt)3
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/FlowEngineTest.kt210
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/FlowTimerQueueTest.kt385
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/mux/ForwardingFlowMultiplexerTest.kt72
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/mux/MaxMinFlowMultiplexerTest.kt55
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/sink/FlowSinkTest.kt131
-rw-r--r--opendc-simulator/opendc-simulator-network/src/main/java/org/opendc/simulator/network/SimNetworkLink.java77
-rw-r--r--opendc-simulator/opendc-simulator-network/src/main/java/org/opendc/simulator/network/SimNetworkPort.java110
-rw-r--r--opendc-simulator/opendc-simulator-network/src/main/java/org/opendc/simulator/network/SimNetworkSink.java70
-rw-r--r--opendc-simulator/opendc-simulator-network/src/main/java/org/opendc/simulator/network/SimNetworkSwitch.java35
-rw-r--r--opendc-simulator/opendc-simulator-network/src/main/java/org/opendc/simulator/network/SimNetworkSwitchVirtual.java107
-rw-r--r--opendc-simulator/opendc-simulator-network/src/test/kotlin/org/opendc/simulator/network/SimNetworkLinkTest.kt91
-rw-r--r--opendc-simulator/opendc-simulator-network/src/test/kotlin/org/opendc/simulator/network/SimNetworkSinkTest.kt153
-rw-r--r--opendc-simulator/opendc-simulator-network/src/test/kotlin/org/opendc/simulator/network/SimNetworkSwitchVirtualTest.kt77
-rw-r--r--opendc-simulator/opendc-simulator-network/src/test/kotlin/org/opendc/simulator/network/TestSource.kt56
-rw-r--r--opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimPdu.java141
-rw-r--r--opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimPowerInlet.java53
-rw-r--r--opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimPowerOutlet.java91
-rw-r--r--opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimPowerSource.java71
-rw-r--r--opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimUps.java137
-rw-r--r--opendc-simulator/opendc-simulator-power/src/test/kotlin/org/opendc/simulator/power/SimPduTest.kt133
-rw-r--r--opendc-simulator/opendc-simulator-power/src/test/kotlin/org/opendc/simulator/power/SimPowerSourceTest.kt155
-rw-r--r--opendc-simulator/opendc-simulator-power/src/test/kotlin/org/opendc/simulator/power/SimUpsTest.kt108
-rw-r--r--opendc-simulator/opendc-simulator-power/src/test/kotlin/org/opendc/simulator/power/TestInlet.kt49
124 files changed, 3109 insertions, 12355 deletions
diff --git a/opendc-simulator/opendc-simulator-compute/build.gradle.kts b/opendc-simulator/opendc-simulator-compute/build.gradle.kts
index 0ea0c252..246fa5e8 100644
--- a/opendc-simulator/opendc-simulator-compute/build.gradle.kts
+++ b/opendc-simulator/opendc-simulator-compute/build.gradle.kts
@@ -29,8 +29,6 @@ plugins {
dependencies {
api(projects.opendcSimulator.opendcSimulatorFlow)
- api(projects.opendcSimulator.opendcSimulatorPower)
- api(projects.opendcSimulator.opendcSimulatorNetwork)
implementation(projects.opendcSimulator.opendcSimulatorCore)
testImplementation(libs.slf4j.simple)
diff --git a/opendc-simulator/opendc-simulator-compute/src/jmh/kotlin/org/opendc/simulator/compute/SimMachineBenchmarks.kt b/opendc-simulator/opendc-simulator-compute/src/jmh/kotlin/org/opendc/simulator/compute/SimMachineBenchmarks.kt
index 5975f944..8d8f4ef8 100644
--- a/opendc-simulator/opendc-simulator-compute/src/jmh/kotlin/org/opendc/simulator/compute/SimMachineBenchmarks.kt
+++ b/opendc-simulator/opendc-simulator-compute/src/jmh/kotlin/org/opendc/simulator/compute/SimMachineBenchmarks.kt
@@ -24,12 +24,13 @@ package org.opendc.simulator.compute
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
-import org.opendc.simulator.compute.kernel.SimHypervisor
-import org.opendc.simulator.compute.model.Cpu
-import org.opendc.simulator.compute.model.MachineModel
-import org.opendc.simulator.compute.model.MemoryUnit
-import org.opendc.simulator.compute.model.ProcessingNode
-import org.opendc.simulator.compute.workload.SimTrace
+import org.opendc.simulator.compute.old.SimBareMetalMachine
+import org.opendc.simulator.compute.old.kernel.SimHypervisor
+import org.opendc.simulator.compute.old.model.CpuModel
+import org.opendc.simulator.compute.old.model.MachineModel
+import org.opendc.simulator.compute.old.model.MemoryUnit
+import org.opendc.simulator.compute.old.model.ProcessingNode
+import org.opendc.simulator.compute.old.workload.SimTrace
import org.opendc.simulator.flow2.FlowEngine
import org.opendc.simulator.flow2.mux.FlowMultiplexerFactory
import org.opendc.simulator.kotlin.runSimulation
@@ -60,7 +61,7 @@ class SimMachineBenchmarks {
MachineModel(
// cpus
List(cpuNode.coreCount) {
- Cpu(
+ CpuModel(
cpuNode,
it,
1000.0,
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimAbstractMachine.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimAbstractMachine.java
deleted file mode 100644
index 3a9e35c1..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimAbstractMachine.java
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * Copyright (c) 2022 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 java.util.HashMap;
-import java.util.Map;
-import java.util.function.Consumer;
-import org.opendc.simulator.compute.device.SimNetworkAdapter;
-import org.opendc.simulator.compute.model.MachineModel;
-import org.opendc.simulator.compute.model.MemoryUnit;
-import org.opendc.simulator.compute.workload.SimWorkload;
-import org.opendc.simulator.flow2.FlowGraph;
-import org.opendc.simulator.flow2.Inlet;
-import org.opendc.simulator.flow2.Outlet;
-import org.opendc.simulator.flow2.sink.SimpleFlowSink;
-import org.opendc.simulator.flow2.util.FlowTransformer;
-import org.opendc.simulator.flow2.util.FlowTransforms;
-
-/**
- * Abstract implementation of the {@link SimMachine} interface.
- */
-public abstract class SimAbstractMachine implements SimMachine {
- private final MachineModel model;
-
- private SimAbstractMachineContext activeContext;
-
- /**
- * Construct a {@link SimAbstractMachine} instance.
- *
- * @param model The model of the machine.
- */
- public SimAbstractMachine(MachineModel model) {
- this.model = model;
- }
-
- @Override
- public final MachineModel getModel() {
- return model;
- }
-
- @Override
- public final SimMachineContext startWorkload(
- SimWorkload workload, Map<String, Object> meta, Consumer<Exception> completion) {
- if (activeContext != null) {
- throw new IllegalStateException("A machine cannot run multiple workloads concurrently");
- }
-
- final SimAbstractMachineContext ctx = createContext(workload, new HashMap<>(meta), completion);
- ctx.start();
- return ctx;
- }
-
- @Override
- public final void cancel() {
- final SimAbstractMachineContext context = activeContext;
- if (context != null) {
- context.shutdown();
- }
- }
-
- /**
- * Construct a new {@link SimAbstractMachineContext} instance representing the active execution.
- *
- * @param workload The workload to start on the machine.
- * @param meta The metadata to pass to the workload.
- * @param completion A block that is invoked when the workload completes carrying an exception if thrown by the workload.
- */
- protected abstract SimAbstractMachineContext createContext(
- SimWorkload workload, Map<String, Object> meta, Consumer<Exception> completion);
-
- /**
- * Return the active {@link SimAbstractMachineContext} instance (if any).
- */
- protected SimAbstractMachineContext getActiveContext() {
- return activeContext;
- }
-
- /**
- * The execution context in which the workload runs.
- */
- public abstract static class SimAbstractMachineContext implements SimMachineContext {
- private final SimAbstractMachine machine;
- private final SimWorkload workload;
- private final Map<String, Object> meta;
- private final Consumer<Exception> completion;
- private boolean isClosed;
- private SimWorkload snapshot;
-
- /**
- * Construct a new {@link SimAbstractMachineContext} instance.
- *
- * @param machine The {@link SimAbstractMachine} to which the context belongs.
- * @param workload The {@link SimWorkload} to which the context belongs.
- * @param meta The metadata passed to the context.
- * @param completion A block that is invoked when the workload completes carrying an exception if thrown by the workload.
- */
- public SimAbstractMachineContext(
- SimAbstractMachine machine,
- SimWorkload workload,
- Map<String, Object> meta,
- Consumer<Exception> completion) {
- this.machine = machine;
- this.workload = workload;
- this.meta = meta;
- this.completion = completion;
- }
-
- @Override
- public final Map<String, Object> getMeta() {
- return meta;
- }
-
- @Override
- public void makeSnapshot(long now) {
- this.snapshot = workload.getSnapshot();
- }
-
- @Override
- public SimWorkload getSnapshot(long now) {
- return this.snapshot;
- }
-
- @Override
- public void reset() {
- final FlowGraph graph = getMemory().getInput().getGraph();
-
- final Inlet inlet = getCpu().getInput();
- graph.disconnect(inlet);
-
- graph.disconnect(getMemory().getInput());
-
- for (SimNetworkInterface ifx : getNetworkInterfaces()) {
- ((NetworkAdapter) ifx).disconnect();
- }
-
- for (SimStorageInterface storage : getStorageInterfaces()) {
- StorageDevice impl = (StorageDevice) storage;
- graph.disconnect(impl.getRead());
- graph.disconnect(impl.getWrite());
- }
- }
-
- @Override
- public final void shutdown() {
- shutdown(null);
- }
-
- @Override
- public final void shutdown(Exception cause) {
- if (isClosed) {
- return;
- }
-
- isClosed = true;
- final SimAbstractMachine machine = this.machine;
- assert machine.activeContext == this : "Invariant violation: multiple contexts active for a single machine";
- machine.activeContext = null;
-
- // Cancel all the resources associated with the machine
- doCancel();
-
- try {
- workload.onStop(this);
- } catch (Exception e) {
- if (cause == null) {
- cause = e;
- } else {
- cause.addSuppressed(e);
- }
- }
-
- completion.accept(cause);
- }
-
- /**
- * Start this context.
- */
- final void start() {
- try {
- machine.activeContext = this;
- workload.onStart(this);
- } catch (Exception cause) {
- shutdown(cause);
- }
- }
-
- /**
- * Run the stop procedures for the resources associated with the machine.
- */
- protected void doCancel() {
- reset();
- }
-
- @Override
- public String toString() {
- return "SimAbstractMachine.Context";
- }
- }
-
- /**
- * The [SimMemory] implementation for a machine.
- */
- public static final class Memory implements SimMemory {
- private final SimpleFlowSink sink;
- private final MemoryUnit memoryUnit;
-
- public Memory(FlowGraph graph, MemoryUnit memoryUnit) {
-
- this.memoryUnit = memoryUnit;
- this.sink = new SimpleFlowSink(graph, (float) memoryUnit.getSize());
- }
-
- @Override
- public double getCapacity() {
- return sink.getCapacity();
- }
-
- @Override
- public MemoryUnit getMemoryUnit() {
- return memoryUnit;
- }
-
- @Override
- public Inlet getInput() {
- return sink.getInput();
- }
-
- @Override
- public String toString() {
- return "SimAbstractMachine.Memory";
- }
- }
-
- /**
- * A {@link SimNetworkAdapter} implementation for a machine.
- */
- public static class NetworkAdapter extends SimNetworkAdapter implements SimNetworkInterface {
- private final org.opendc.simulator.compute.model.NetworkAdapter model;
- private final FlowTransformer tx;
- private final FlowTransformer rx;
- private final String name;
-
- /**
- * Construct a {@link NetworkAdapter}.
- */
- public NetworkAdapter(FlowGraph graph, org.opendc.simulator.compute.model.NetworkAdapter model, int index) {
- this.model = model;
- this.tx = new FlowTransformer(graph, FlowTransforms.noop());
- this.rx = new FlowTransformer(graph, FlowTransforms.noop());
- this.name = "eth" + index;
- }
-
- @Override
- public String getName() {
- return name;
- }
-
- @Override
- public Inlet getTx() {
- return tx.getInput();
- }
-
- @Override
- public Outlet getRx() {
- return rx.getOutput();
- }
-
- @Override
- public double getBandwidth() {
- return model.getBandwidth();
- }
-
- @Override
- protected Outlet getOutlet() {
- return tx.getOutput();
- }
-
- @Override
- protected Inlet getInlet() {
- return rx.getInput();
- }
-
- @Override
- public String toString() {
- return "SimAbstractMachine.NetworkAdapterImpl[name=" + name + ", bandwidth=" + model.getBandwidth()
- + "Mbps]";
- }
- }
-
- /**
- * A {@link SimStorageInterface} implementation for a machine.
- */
- public static class StorageDevice implements SimStorageInterface {
- private final org.opendc.simulator.compute.model.StorageDevice model;
- private final SimpleFlowSink read;
- private final SimpleFlowSink write;
- private final String name;
-
- /**
- * Construct a {@link StorageDevice}.
- */
- public StorageDevice(FlowGraph graph, org.opendc.simulator.compute.model.StorageDevice model, int index) {
- this.model = model;
- this.read = new SimpleFlowSink(graph, (float) model.getReadBandwidth());
- this.write = new SimpleFlowSink(graph, (float) model.getWriteBandwidth());
- this.name = "disk" + index;
- }
-
- @Override
- public String getName() {
- return name;
- }
-
- @Override
- public Inlet getRead() {
- return read.getInput();
- }
-
- @Override
- public Inlet getWrite() {
- return write.getInput();
- }
-
- @Override
- public double getCapacity() {
- return model.getCapacity();
- }
-
- @Override
- public String toString() {
- return "SimAbstractMachine.StorageDeviceImpl[name=" + name + ", capacity=" + model.getCapacity() + "MB]";
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimBareMetalMachine.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimBareMetalMachine.java
deleted file mode 100644
index 6acc605e..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimBareMetalMachine.java
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * Copyright (c) 2022 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 java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Consumer;
-import org.opendc.simulator.compute.device.SimPeripheral;
-import org.opendc.simulator.compute.model.Cpu;
-import org.opendc.simulator.compute.model.MachineModel;
-import org.opendc.simulator.compute.workload.SimWorkload;
-import org.opendc.simulator.flow2.FlowGraph;
-import org.opendc.simulator.flow2.InPort;
-import org.opendc.simulator.flow2.Inlet;
-
-/**
- * A simulated bare-metal machine that is able to run a single workload.
- *
- * <p>
- * A {@link 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 {@link #startWorkload(SimWorkload, Map, Consumer)} )}.
- */
-public final class SimBareMetalMachine extends SimAbstractMachine {
- /**
- * The {@link FlowGraph} in which the simulation takes places.
- */
- private final FlowGraph graph;
-
- /**
- * The {@link SimPsu} of this bare metal machine.
- */
- private final SimPsu psu;
-
- /**
- * The resources of this machine.
- */
- private final SimCpu cpu;
-
- private final Memory memory;
- private final List<NetworkAdapter> net;
- private final List<StorageDevice> disk;
-
- /**
- * Construct a {@link SimBareMetalMachine} instance.
- *
- * @param graph The {@link FlowGraph} to which the machine belongs.
- * @param model The machine model to simulate.
- * @param psuFactory The {@link SimPsuFactory} to construct the power supply of the machine.
- */
- private SimBareMetalMachine(FlowGraph graph, MachineModel model, SimPsuFactory psuFactory) {
- super(model);
-
- this.graph = graph;
- this.psu = psuFactory.newPsu(this, graph);
-
- this.cpu = new SimCpu(psu, model.getCpu(), 0);
- this.memory = new Memory(graph, model.getMemory());
-
- int netIndex = 0;
- final ArrayList<NetworkAdapter> net = new ArrayList<>();
- this.net = net;
- for (org.opendc.simulator.compute.model.NetworkAdapter adapter : model.getNetwork()) {
- net.add(new NetworkAdapter(graph, adapter, netIndex++));
- }
-
- int diskIndex = 0;
- final ArrayList<StorageDevice> disk = new ArrayList<>();
- this.disk = disk;
- for (org.opendc.simulator.compute.model.StorageDevice device : model.getStorage()) {
- disk.add(new StorageDevice(graph, device, diskIndex++));
- }
- }
-
- /**
- * Create a {@link SimBareMetalMachine} instance.
- *
- * @param graph The {@link FlowGraph} to which the machine belongs.
- * @param model The machine model to simulate.
- * @param psuFactory The {@link SimPsuFactory} to construct the power supply of the machine.
- */
- public static SimBareMetalMachine create(FlowGraph graph, MachineModel model, SimPsuFactory psuFactory) {
- return new SimBareMetalMachine(graph, model, psuFactory);
- }
-
- /**
- * Create a {@link SimBareMetalMachine} instance with a no-op PSU.
- *
- * @param graph The {@link FlowGraph} to which the machine belongs.
- * @param model The machine model to simulate.
- */
- public static SimBareMetalMachine create(FlowGraph graph, MachineModel model) {
- return new SimBareMetalMachine(graph, model, SimPsuFactories.noop());
- }
-
- /**
- * Return the {@link SimPsu} belonging to this bare metal machine.
- */
- public SimPsu getPsu() {
- return psu;
- }
-
- /**
- * Return the list of peripherals attached to this bare metal machine.
- */
- @Override
- public List<? extends SimPeripheral> getPeripherals() {
- return Collections.unmodifiableList(net);
- }
-
- /**
- * Return the CPU capacity of the machine in MHz.
- */
- public double getCpuCapacity() {
- final SimAbstractMachineContext context = (SimAbstractMachineContext) getActiveContext();
-
- if (context == null) {
- return 0.0;
- }
-
- return cpu.getFrequency();
- }
-
- /**
- * The CPU demand of the machine in MHz.
- */
- public double getCpuDemand() {
- final SimAbstractMachineContext context = (SimAbstractMachineContext) getActiveContext();
-
- if (context == null) {
- return 0.0;
- }
-
- return cpu.getDemand();
- }
-
- /**
- * The CPU usage of the machine in MHz.
- */
- public double getCpuUsage() {
- final SimAbstractMachineContext context = (SimAbstractMachineContext) getActiveContext();
-
- if (context == null) {
- return 0.0;
- }
-
- return cpu.getSpeed();
- }
-
- @Override
- protected SimAbstractMachine.SimAbstractMachineContext createContext(
- SimWorkload workload, Map<String, Object> meta, Consumer<Exception> completion) {
- return new SimAbstractMachineContext(this, workload, meta, completion);
- }
-
- /**
- * The execution context for a {@link SimBareMetalMachine}.
- */
- private static final class SimAbstractMachineContext extends SimAbstractMachine.SimAbstractMachineContext {
- private final FlowGraph graph;
- private final SimCpu cpu;
- private final Memory memory;
- private final List<NetworkAdapter> net;
- private final List<StorageDevice> disk;
-
- private SimAbstractMachineContext(
- SimBareMetalMachine machine,
- SimWorkload workload,
- Map<String, Object> meta,
- Consumer<Exception> completion) {
- super(machine, workload, meta, completion);
-
- this.graph = machine.graph;
- this.cpu = machine.cpu;
- this.memory = machine.memory;
- this.net = machine.net;
- this.disk = machine.disk;
- }
-
- @Override
- public FlowGraph getGraph() {
- return graph;
- }
-
- @Override
- public SimCpu getCpu() {
- return cpu;
- }
-
- @Override
- public SimMemory getMemory() {
- return memory;
- }
-
- @Override
- public List<? extends SimNetworkInterface> getNetworkInterfaces() {
- return net;
- }
-
- @Override
- public List<? extends SimStorageInterface> getStorageInterfaces() {
- return disk;
- }
- }
-
- /**
- * A {@link SimProcessingUnit} of a bare-metal machine.
- */
- private static final class SimCpu implements SimProcessingUnit {
- private final SimPsu psu;
- private final Cpu cpuModel;
- private final InPort port;
-
- private SimCpu(SimPsu psu, Cpu cpuModel, int id) {
- this.psu = psu;
- this.cpuModel = cpuModel;
- this.port = psu.getCpuPower(id, cpuModel);
-
- this.port.pull((float) cpuModel.getTotalCapacity());
- }
-
- @Override
- public double getFrequency() {
- return port.getCapacity();
- }
-
- @Override
- public void setFrequency(double frequency) {
- // Clamp the capacity of the CPU between [0.0, maxFreq]
- frequency = Math.max(0, Math.min(cpuModel.getTotalCapacity(), frequency));
- psu.setCpuFrequency(port, frequency);
- }
-
- @Override
- public double getDemand() {
- return port.getDemand();
- }
-
- @Override
- public double getSpeed() {
- return port.getRate();
- }
-
- @Override
- public org.opendc.simulator.compute.model.Cpu getCpuModel() {
- return cpuModel;
- }
-
- @Override
- public Inlet getInput() {
- return port;
- }
-
- @Override
- public String toString() {
- return "SimBareMetalMachine.Cpu[model=" + cpuModel + "]";
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimMachine.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimMachine.java
deleted file mode 100644
index 1f86aa02..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimMachine.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (c) 2022 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 java.util.List;
-import java.util.Map;
-import java.util.function.Consumer;
-import org.opendc.simulator.compute.device.SimPeripheral;
-import org.opendc.simulator.compute.model.MachineModel;
-import org.opendc.simulator.compute.workload.SimWorkload;
-
-/**
- * A generic machine that is able to execute {@link SimWorkload} objects.
- */
-public interface SimMachine {
- /**
- * Return the model of the machine containing its specifications.
- */
- MachineModel getModel();
-
- /**
- * Return the peripherals attached to the machine.
- */
- List<? extends SimPeripheral> getPeripherals();
-
- /**
- * Start the specified {@link SimWorkload} on this machine.
- *
- * @param workload The workload to start on the machine.
- * @param meta The metadata to pass to the workload.
- * @param completion A block that is invoked when the workload completes carrying an exception if thrown by the workload.
- * @return A {@link SimMachineContext} that represents the execution context for the workload.
- * @throws IllegalStateException if a workload is already active on the machine or if the machine is closed.
- */
- SimMachineContext startWorkload(SimWorkload workload, Map<String, Object> meta, Consumer<Exception> completion);
-
- /**
- * Cancel the active workload on this machine (if any).
- */
- void cancel();
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimMachineContext.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimMachineContext.java
deleted file mode 100644
index 887967fb..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimMachineContext.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (c) 2022 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 java.util.List;
-import java.util.Map;
-import java.util.function.Consumer;
-import org.opendc.simulator.compute.workload.SimWorkload;
-import org.opendc.simulator.flow2.FlowGraph;
-
-/**
- * A simulated execution context in which a bootable image runs.
- *
- * <p>
- * This interface represents the interface between the running image (e.g. operating system) and the physical
- * or virtual firmware on which the image runs.
- */
-public interface SimMachineContext {
- /**
- * Return the {@link FlowGraph} in which the workload executes.
- */
- FlowGraph getGraph();
-
- /**
- * Return the metadata associated with the context.
- * <p>
- * Users can pass this metadata to the workload via {@link SimMachine#startWorkload(SimWorkload, Map, Consumer)}.
- */
- Map<String, Object> getMeta();
-
- /**
- * Return the CPUs available on the machine.
- */
- SimProcessingUnit getCpu();
-
- /**
- * Return the memory interface of the machine.
- */
- SimMemory getMemory();
-
- /**
- * Return the network interfaces available to the workload.
- */
- List<? extends SimNetworkInterface> getNetworkInterfaces();
-
- /**
- * Return the storage devices available to the workload.
- */
- List<? extends SimStorageInterface> getStorageInterfaces();
-
- /**
- * Create a snapshot of the {@link SimWorkload} running on this machine.
- *
- * @throws UnsupportedOperationException if the workload does not support snapshotting.
- */
- void makeSnapshot(long now);
-
- SimWorkload getSnapshot(long now);
-
- /**
- * Reset all resources of the machine.
- */
- void reset();
-
- /**
- * Shutdown the workload.
- */
- void shutdown();
-
- /**
- * Shutdown the workload due to failure.
- *
- * @param cause The cause for shutting down the workload.
- */
- void shutdown(Exception cause);
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimMemory.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimMemory.java
deleted file mode 100644
index 85027f28..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimMemory.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2022 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.flow2.sink.FlowSink;
-
-/**
- * An interface to control the memory usage of simulated workloads.
- */
-public interface SimMemory extends FlowSink {
- /**
- * Return the total capacity of the memory (in MBs).
- */
- double getCapacity();
-
- /**
- * Return the models representing the static information of the memory units supporting this interface.
- */
- MemoryUnit getMemoryUnit();
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimNetworkInterface.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimNetworkInterface.java
deleted file mode 100644
index 4b623e59..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimNetworkInterface.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2022 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.flow2.Inlet;
-import org.opendc.simulator.flow2.Outlet;
-
-/**
- * A firmware interface to a network adapter.
- */
-public interface SimNetworkInterface {
- /**
- * Return the name of the network interface.
- */
- String getName();
-
- /**
- * Return the unidirectional bandwidth of the network interface in Mbps.
- */
- double getBandwidth();
-
- /**
- * Return the inlet for the "transmit" channel of the network interface.
- */
- Inlet getTx();
-
- /**
- * Return the outlet for the "receive" channel of the network interface.
- */
- Outlet getRx();
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimProcessingUnit.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimProcessingUnit.java
deleted file mode 100644
index 213c3d4f..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimProcessingUnit.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (c) 2022 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.Cpu;
-import org.opendc.simulator.flow2.sink.FlowSink;
-
-/**
- * A simulated processing unit.
- */
-public interface SimProcessingUnit extends FlowSink {
- /**
- * Return the base clock frequency of the processing unit (in MHz).
- */
- double getFrequency();
-
- /**
- * Adjust the base clock frequency of the processing unit.
- *
- * <p>
- * The CPU may or may not round the new frequency to one of its pre-defined frequency steps.
- *
- * @param frequency The new frequency to set the clock of the processing unit to.
- * @throws UnsupportedOperationException if the base clock cannot be adjusted.
- */
- void setFrequency(double frequency);
-
- /**
- * The demand on the processing unit.
- */
- double getDemand();
-
- /**
- * The speed of the processing unit.
- */
- double getSpeed();
-
- /**
- * The model representing the static properties of the processing unit.
- */
- Cpu getCpuModel();
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimPsu.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimPsu.java
deleted file mode 100644
index e7718604..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimPsu.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2022 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.Cpu;
-import org.opendc.simulator.flow2.InPort;
-import org.opendc.simulator.power.SimPowerInlet;
-
-/**
- * A power supply unit in a {@link SimBareMetalMachine}.
- *
- * <p>
- * This class manages the computation of power usage for a {@link SimBareMetalMachine} based on the resource usage.
- */
-public abstract class SimPsu extends SimPowerInlet {
- /**
- * Return the power demand of the machine (in W) measured in the PSU.
- * <p>
- * This method provides access to the power consumption of the machine before PSU losses are applied.
- */
- public abstract double getPowerDemand();
-
- /**
- * Return the instantaneous power usage of the machine (in W) measured at the inlet of the power supply.
- */
- public abstract double getPowerDraw();
-
- /**
- * Return the cumulated energy usage of the machine (in J) measured at the inlet of the powers supply.
- */
- public abstract double getEnergyUsage();
-
- /**
- * Return an {@link InPort} that converts processing demand (in MHz) into energy demand (J) for the specified CPU
- * <code>model</code>.
- *
- * @param id The unique identifier of the CPU for this machine.
- * @param model The details of the processing unit.
- */
- abstract InPort getCpuPower(int id, Cpu model);
-
- /**
- * This method is invoked when the CPU frequency is changed for the specified <code>port</code>.
- *
- * @param port The {@link InPort} for which the capacity is changed.
- * @param capacity The capacity to change to.
- */
- void setCpuFrequency(InPort port, double capacity) {
- port.pull((float) capacity);
- }
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimPsuFactories.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimPsuFactories.java
deleted file mode 100644
index 27327616..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimPsuFactories.java
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Copyright (c) 2022 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 java.time.InstantSource;
-import org.jetbrains.annotations.NotNull;
-import org.opendc.simulator.compute.model.Cpu;
-import org.opendc.simulator.compute.power.CpuPowerModel;
-import org.opendc.simulator.flow2.FlowGraph;
-import org.opendc.simulator.flow2.FlowStage;
-import org.opendc.simulator.flow2.FlowStageLogic;
-import org.opendc.simulator.flow2.InHandler;
-import org.opendc.simulator.flow2.InPort;
-import org.opendc.simulator.flow2.OutPort;
-import org.opendc.simulator.flow2.Outlet;
-
-/**
- * A collection {@link SimPsu} implementations.
- */
-public class SimPsuFactories {
- private SimPsuFactories() {}
-
- /**
- * Return a {@link SimPsuFactory} of {@link SimPsu} implementations that do not measure any power consumption.
- *
- * <p>
- * This implementation has the lowest performance impact and users are advised to use this factory if they do not
- * consider power consumption in their experiments.
- */
- public static SimPsuFactory noop() {
- return NoopPsu.FACTORY;
- }
-
- /**
- * Return a {@link SimPsuFactory} of {@link SimPsu} implementations that use a {@link CpuPowerModel} to estimate the
- * power consumption of a machine based on its CPU utilization.
- *
- * @param model The power model to estimate the power consumption based on the CPU usage.
- */
- public static SimPsuFactory simple(CpuPowerModel model) {
- return (machine, graph) -> new SimplePsu(graph, model);
- }
-
- /**
- * A {@link SimPsu} implementation that does not attempt to measure power consumption.
- */
- private static final class NoopPsu extends SimPsu implements FlowStageLogic {
- private static final SimPsuFactory FACTORY = (machine, graph) -> new NoopPsu(graph);
-
- private final FlowStage stage;
- private final OutPort out;
-
- NoopPsu(FlowGraph graph) {
- stage = graph.newStage(this);
- out = stage.getOutlet("out");
- out.setMask(true);
- }
-
- @Override
- public double getPowerDemand() {
- return 0;
- }
-
- @Override
- public double getPowerDraw() {
- return 0;
- }
-
- @Override
- public double getEnergyUsage() {
- return 0;
- }
-
- @Override
- InPort getCpuPower(int id, Cpu model) {
- final InPort port = stage.getInlet("cpu" + id);
- port.setMask(true);
- return port;
- }
-
- @Override
- public long onUpdate(FlowStage ctx, long now) {
- return Long.MAX_VALUE;
- }
-
- @NotNull
- @Override
- public Outlet getFlowOutlet() {
- return out;
- }
- }
-
- /**
- * A {@link SimPsu} implementation that estimates the power consumption based on CPU usage.
- */
- private static final class SimplePsu extends SimPsu implements FlowStageLogic {
- private final FlowStage stage;
- private final OutPort out;
- private final CpuPowerModel model;
- private final InstantSource clock;
-
- private double targetFreq;
- private double totalUsage;
- private long lastUpdate;
-
- private double powerDraw;
- private double energyUsage;
-
- private final InHandler handler = new InHandler() {
- @Override
- public void onPush(InPort port, float demand) {
- totalUsage += -port.getDemand() + demand;
- }
-
- @Override
- public void onUpstreamFinish(InPort port, Throwable cause) {
- totalUsage -= port.getDemand();
- }
- };
-
- SimplePsu(FlowGraph graph, CpuPowerModel model) {
- this.stage = graph.newStage(this);
- this.model = model;
- this.clock = graph.getEngine().getClock();
- this.out = stage.getOutlet("out");
- this.out.setMask(true);
-
- lastUpdate = graph.getEngine().getClock().millis();
- }
-
- @Override
- public double getPowerDemand() {
- return totalUsage;
- }
-
- @Override
- public double getPowerDraw() {
- return powerDraw;
- }
-
- @Override
- public double getEnergyUsage() {
- updateEnergyUsage(clock.millis());
- return energyUsage;
- }
-
- @Override
- InPort getCpuPower(int id, Cpu model) {
- targetFreq += model.getTotalCapacity();
-
- final InPort port = stage.getInlet("cpu" + id);
- port.setHandler(handler);
- return port;
- }
-
- @Override
- void setCpuFrequency(InPort port, double capacity) {
- targetFreq += -port.getCapacity() + capacity;
-
- super.setCpuFrequency(port, capacity);
- }
-
- @Override
- public long onUpdate(FlowStage ctx, long now) {
- updateEnergyUsage(now);
-
- double usage = model.computePower(totalUsage / targetFreq);
- out.push((float) usage);
- powerDraw = usage;
-
- return Long.MAX_VALUE;
- }
-
- @NotNull
- @Override
- public Outlet getFlowOutlet() {
- return out;
- }
-
- /**
- * Calculate the energy usage up until <code>now</code>.
- */
- private void updateEnergyUsage(long now) {
- long lastUpdate = this.lastUpdate;
- this.lastUpdate = now;
-
- long duration = now - lastUpdate;
- if (duration > 0) {
- // Compute the energy usage of the machine
- energyUsage += powerDraw * duration * 0.001;
- }
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimPsuFactory.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimPsuFactory.java
deleted file mode 100644
index 872e7016..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimPsuFactory.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2022 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.flow2.FlowGraph;
-
-/**
- * A factory interface for {@link SimPsu} implementations.
- */
-public interface SimPsuFactory {
- /**
- * Construct a new {@link SimPsu} for the specified <code>machine</code>.
- *
- * @param machine The machine to construct the power supply for.
- * @param graph The {@link FlowGraph} used for the simulation.
- */
- SimPsu newPsu(SimMachine machine, FlowGraph graph);
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimStorageInterface.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimStorageInterface.java
deleted file mode 100644
index 341122dc..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimStorageInterface.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2022 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.flow2.Inlet;
-
-/**
- * A firmware interface to a storage device.
- */
-public interface SimStorageInterface {
- /**
- * Return the name of the network interface.
- */
- String getName();
-
- /**
- * Return the capacity of the storage device in MBs.
- */
- double getCapacity();
-
- /**
- * Return the inlet for the read operations of the storage device.
- */
- Inlet getRead();
-
- /**
- * Return the inlet for the write operation of the storage device.
- */
- Inlet getWrite();
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/CPUPowerModelsFactory.kt b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/cpu/CPUPowerModelsFactory.kt
index 2c64944c..3600756b 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/CPUPowerModelsFactory.kt
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/cpu/CPUPowerModelsFactory.kt
@@ -20,7 +20,7 @@
* SOFTWARE.
*/
-package org.opendc.simulator.compute.power
+package org.opendc.simulator.compute.cpu
// TODO: couple this correctly
public enum class CPUPowerModel {
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/CpuPowerModel.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/cpu/CpuPowerModel.java
index 73f9357d..4323294e 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/CpuPowerModel.java
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/cpu/CpuPowerModel.java
@@ -20,9 +20,9 @@
* SOFTWARE.
*/
-package org.opendc.simulator.compute.power;
+package org.opendc.simulator.compute.cpu;
-import org.opendc.simulator.compute.SimMachine;
+import org.opendc.simulator.compute.machine.SimMachine;
/**
* A model for estimating the power usage of a {@link SimMachine} based on the CPU usage.
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/CpuPowerModels.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/cpu/CpuPowerModels.java
index 4e62e67f..b91bd7e2 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/CpuPowerModels.java
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/cpu/CpuPowerModels.java
@@ -20,7 +20,7 @@
* SOFTWARE.
*/
-package org.opendc.simulator.compute.power;
+package org.opendc.simulator.compute.cpu;
import java.util.Arrays;
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/cpu/SimCpu.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/cpu/SimCpu.java
new file mode 100644
index 00000000..60c877e9
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/cpu/SimCpu.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2024 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package org.opendc.simulator.compute.cpu;
+
+import org.opendc.simulator.compute.machine.PerformanceCounters;
+import org.opendc.simulator.compute.models.CpuModel;
+import org.opendc.simulator.engine.FlowConsumer;
+import org.opendc.simulator.engine.FlowEdge;
+import org.opendc.simulator.engine.FlowGraph;
+import org.opendc.simulator.engine.FlowNode;
+import org.opendc.simulator.engine.FlowSupplier;
+
+/**
+ * A {@link SimCpu} of a machine.
+ */
+public final class SimCpu extends FlowNode implements FlowSupplier, FlowConsumer {
+ private final CpuModel cpuModel;
+
+ private final CpuPowerModel cpuPowerModel;
+
+ private float currentCpuDemand = 0.0f; // cpu capacity demanded by the mux
+ private float currentCpuUtilization = 0.0f;
+ private float currentPowerDemand = 0.0f; // power demanded of the psu
+ private float currentCpuSupplied = 0.0f; // cpu capacity supplied to the mux
+ private float currentPowerSupplied = 0.0f; // cpu capacity supplied by the psu
+
+ private float maxCapacity;
+
+ private PerformanceCounters performanceCounters = new PerformanceCounters();
+ private long lastCounterUpdate;
+ private final float cpuFrequencyInv;
+
+ private FlowEdge muxEdge;
+ private FlowEdge psuEdge;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Basic Getters and Setters
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ public double getFrequency() {
+ return cpuModel.getTotalCapacity();
+ }
+
+ public void setFrequency(double frequency) {
+ // Clamp the capacity of the CPU between [0.0, maxFreq]
+ frequency = Math.max(0, Math.min(this.maxCapacity, frequency));
+ // psu.setCpuFrequency(muxInPort, frequency);
+ }
+
+ @Override
+ public float getCapacity() {
+ return maxCapacity;
+ }
+
+ public PerformanceCounters getPerformanceCounters() {
+ return performanceCounters;
+ }
+
+ public double getPowerDraw() {
+ return this.currentPowerSupplied;
+ }
+
+ public double getDemand() {
+ return this.currentCpuDemand;
+ }
+
+ public double getSpeed() {
+ return this.currentCpuSupplied;
+ }
+
+ public CpuModel getCpuModel() {
+ return cpuModel;
+ }
+
+ @Override
+ public String toString() {
+ return "SimBareMetalMachine.Cpu[model=" + cpuModel + "]";
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Constructors
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ public SimCpu(FlowGraph graph, CpuModel cpuModel, int id) {
+ super(graph);
+ this.cpuModel = cpuModel;
+ this.maxCapacity = this.cpuModel.getTotalCapacity();
+
+ // TODO: connect this to the front-end
+ this.cpuPowerModel = CpuPowerModels.linear(400, 200);
+
+ this.lastCounterUpdate = graph.getEngine().getClock().millis();
+
+ this.cpuFrequencyInv = 1 / this.maxCapacity;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // FlowNode related functionality
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public long onUpdate(long now) {
+ updateCounters(now);
+
+ // Calculate Power Demand and send to PSU
+ // TODO: look at the float / double thing
+ float powerDemand = (float) this.cpuPowerModel.computePower((double) this.currentCpuUtilization);
+
+ if (powerDemand != this.currentPowerDemand) {
+ this.pushDemand(this.psuEdge, powerDemand);
+ this.currentPowerDemand = powerDemand;
+ }
+
+ // Calculate the amount of cpu this can provide
+ // TODO: This should be based on the provided power
+ float cpuSupply = this.currentCpuDemand;
+
+ if (cpuSupply != this.currentCpuSupplied) {
+ this.pushSupply(this.muxEdge, cpuSupply);
+ this.currentCpuSupplied = cpuSupply;
+ }
+
+ return Long.MAX_VALUE;
+ }
+
+ public void updateCounters() {
+ this.updateCounters(this.clock.millis());
+ }
+
+ /**
+ * Update the performance counters of the CPU.
+ *
+ * @param now The timestamp at which to update the counter.
+ */
+ public void updateCounters(long now) {
+ long lastUpdate = this.lastCounterUpdate;
+ this.lastCounterUpdate = now;
+ long delta = now - lastUpdate;
+
+ if (delta > 0) {
+ float demand = this.currentCpuDemand;
+ float rate = this.currentCpuSupplied;
+ float capacity = this.maxCapacity;
+
+ final float factor = this.cpuFrequencyInv * delta;
+
+ this.performanceCounters.addCpuActiveTime(Math.round(rate * factor));
+ this.performanceCounters.addCpuIdleTime(Math.round((capacity - rate) * factor));
+ this.performanceCounters.addCpuStealTime(Math.round((demand - rate) * factor));
+ }
+
+ this.performanceCounters.setCpuDemand(this.currentCpuDemand);
+ this.performanceCounters.setCpuSupply(this.currentCpuSupplied);
+ this.performanceCounters.setCpuCapacity(this.maxCapacity);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // FlowGraph Related functionality
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Push new demand to the psu
+ */
+ @Override
+ public void pushDemand(FlowEdge supplierEdge, float newPowerDemand) {
+ this.psuEdge.pushDemand(newPowerDemand);
+ }
+
+ /**
+ * Push updated supply to the mux
+ */
+ @Override
+ public void pushSupply(FlowEdge consumerEdge, float newCpuSupply) {
+ updateCounters();
+ this.currentCpuSupplied = newCpuSupply;
+ this.muxEdge.pushSupply(newCpuSupply);
+ }
+
+ /**
+ * Handle new demand coming in from the mux
+ */
+ @Override
+ public void handleDemand(FlowEdge consumerEdge, float newCpuDemand) {
+ if (newCpuDemand == this.currentCpuDemand) {
+ return;
+ }
+
+ updateCounters();
+ this.currentCpuDemand = newCpuDemand;
+ this.currentCpuUtilization = this.currentCpuDemand / this.maxCapacity;
+
+ this.invalidate();
+ }
+
+ /**
+ * Handle updated supply from the psu
+ */
+ @Override
+ public void handleSupply(FlowEdge supplierEdge, float newPowerSupply) {
+ // TODO: Implement this
+ updateCounters();
+ this.currentPowerSupplied = newPowerSupply;
+
+ this.invalidate();
+ }
+
+ /**
+ * Add a connection to the mux
+ */
+ @Override
+ public void addConsumerEdge(FlowEdge consumerEdge) {
+ this.muxEdge = consumerEdge;
+ }
+
+ /**
+ * Add a connection to the psu
+ */
+ @Override
+ public void addSupplierEdge(FlowEdge supplierEdge) {
+ this.psuEdge = supplierEdge;
+ }
+
+ /**
+ * Remove the connection to the mux
+ */
+ @Override
+ public void removeConsumerEdge(FlowEdge consumerEdge) {
+ this.muxEdge = null;
+ this.invalidate();
+ }
+
+ /**
+ * Remove the connection to the psu
+ */
+ @Override
+ public void removeSupplierEdge(FlowEdge supplierEdge) {
+ this.psuEdge = null;
+ this.invalidate();
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/device/SimNetworkAdapter.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/device/SimNetworkAdapter.java
deleted file mode 100644
index 1c16ceff..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/device/SimNetworkAdapter.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2022 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.device;
-
-import org.opendc.simulator.compute.SimMachine;
-import org.opendc.simulator.network.SimNetworkPort;
-
-/**
- * A simulated network interface card (NIC or network adapter) that can be attached to a {@link SimMachine}.
- */
-public abstract class SimNetworkAdapter extends SimNetworkPort implements SimPeripheral {
- /**
- * Return the unidirectional bandwidth of the network adapter (in Mbps).
- */
- public abstract double getBandwidth();
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/device/SimPeripheral.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/device/SimPeripheral.java
deleted file mode 100644
index 40bd268b..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/device/SimPeripheral.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (c) 2022 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.device;
-
-import org.opendc.simulator.compute.SimMachine;
-
-/**
- * A component that can be attached to a {@link SimMachine}.
- * <p>
- * This interface represents the physical view of the peripheral and should be used to configure the physical properties
- * of the peripheral.
- */
-public interface SimPeripheral {}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/SimHypervisor.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/SimHypervisor.java
deleted file mode 100644
index 42750b0f..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/SimHypervisor.java
+++ /dev/null
@@ -1,933 +0,0 @@
-/*
- * Copyright (c) 2022 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.kernel;
-
-import java.time.InstantSource;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.SplittableRandom;
-import java.util.function.Consumer;
-import org.opendc.simulator.compute.SimAbstractMachine;
-import org.opendc.simulator.compute.SimMachine;
-import org.opendc.simulator.compute.SimMachineContext;
-import org.opendc.simulator.compute.SimMemory;
-import org.opendc.simulator.compute.SimNetworkInterface;
-import org.opendc.simulator.compute.SimProcessingUnit;
-import org.opendc.simulator.compute.SimStorageInterface;
-import org.opendc.simulator.compute.device.SimPeripheral;
-import org.opendc.simulator.compute.kernel.cpufreq.ScalingGovernor;
-import org.opendc.simulator.compute.kernel.cpufreq.ScalingGovernorFactory;
-import org.opendc.simulator.compute.kernel.cpufreq.ScalingPolicy;
-import org.opendc.simulator.compute.kernel.interference.VmInterferenceDomain;
-import org.opendc.simulator.compute.kernel.interference.VmInterferenceMember;
-import org.opendc.simulator.compute.kernel.interference.VmInterferenceProfile;
-import org.opendc.simulator.compute.model.Cpu;
-import org.opendc.simulator.compute.model.MachineModel;
-import org.opendc.simulator.compute.workload.SimWorkload;
-import org.opendc.simulator.flow2.FlowGraph;
-import org.opendc.simulator.flow2.FlowStage;
-import org.opendc.simulator.flow2.FlowStageLogic;
-import org.opendc.simulator.flow2.InHandler;
-import org.opendc.simulator.flow2.InPort;
-import org.opendc.simulator.flow2.Inlet;
-import org.opendc.simulator.flow2.OutHandler;
-import org.opendc.simulator.flow2.OutPort;
-import org.opendc.simulator.flow2.mux.FlowMultiplexer;
-import org.opendc.simulator.flow2.mux.FlowMultiplexerFactory;
-
-/**
- * A SimHypervisor facilitates the execution of multiple concurrent {@link SimWorkload}s, while acting as a single
- * workload to another {@link SimMachine}.
- */
-public final class SimHypervisor implements SimWorkload {
- private final FlowMultiplexerFactory muxFactory;
- private final SplittableRandom random;
- private final ScalingGovernorFactory scalingGovernorFactory;
- private final VmInterferenceDomain interferenceDomain;
-
- private SimHyperVisorContext activeContext;
- private final ArrayList<SimVirtualMachine> vms = new ArrayList<>();
- private final HvCounters counters = new HvCounters();
-
- @Override
- public void setOffset(long now) {}
-
- /**
- * Construct a {@link SimHypervisor} instance.
- *
- * @param muxFactory The factory for the {@link FlowMultiplexer} to multiplex the workloads.
- * @param random A randomness generator for the interference calculations.
- * @param scalingGovernorFactory The factory for the scaling governor to use for scaling the CPU frequency.
- * @param interferenceDomain The interference domain to which the hypervisor belongs.
- */
- private SimHypervisor(
- FlowMultiplexerFactory muxFactory,
- SplittableRandom random,
- ScalingGovernorFactory scalingGovernorFactory,
- VmInterferenceDomain interferenceDomain) {
- this.muxFactory = muxFactory;
- this.random = random;
- this.scalingGovernorFactory = scalingGovernorFactory;
- this.interferenceDomain = interferenceDomain;
- }
-
- /**
- * Create a {@link SimHypervisor} instance.
- *
- * @param muxFactory The factory for the {@link FlowMultiplexer} to multiplex the workloads.
- * @param random A randomness generator for the interference calculations.
- * @param scalingGovernorFactory The factory for the scaling governor to use for scaling the CPU frequency.
- * @param interferenceDomain The interference domain to which the hypervisor belongs.
- */
- public static SimHypervisor create(
- FlowMultiplexerFactory muxFactory,
- SplittableRandom random,
- ScalingGovernorFactory scalingGovernorFactory,
- VmInterferenceDomain interferenceDomain) {
- return new SimHypervisor(muxFactory, random, scalingGovernorFactory, interferenceDomain);
- }
-
- /**
- * Create a {@link SimHypervisor} instance with a default interference domain.
- *
- * @param muxFactory The factory for the {@link FlowMultiplexer} to multiplex the workloads.
- * @param random A randomness generator for the interference calculations.
- * @param scalingGovernorFactory The factory for the scaling governor to use for scaling the CPU frequency.
- */
- public static SimHypervisor create(
- FlowMultiplexerFactory muxFactory, SplittableRandom random, ScalingGovernorFactory scalingGovernorFactory) {
- return create(muxFactory, random, scalingGovernorFactory, new VmInterferenceDomain());
- }
-
- /**
- * Create a {@link SimHypervisor} instance with a default interference domain and scaling governor.
- *
- * @param muxFactory The factory for the {@link FlowMultiplexer} to multiplex the workloads.
- * @param random A randomness generator for the interference calculations.
- */
- public static SimHypervisor create(FlowMultiplexerFactory muxFactory, SplittableRandom random) {
- return create(muxFactory, random, null);
- }
-
- /**
- * Return the performance counters of the hypervisor.
- */
- public SimHypervisorCounters getCounters() {
- return counters;
- }
-
- /**
- * Return the virtual machines running on this hypervisor.
- */
- public List<? extends SimVirtualMachine> getVirtualMachines() {
- return Collections.unmodifiableList(vms);
- }
-
- /**
- * Create a {@link SimVirtualMachine} instance on which users may run a [SimWorkload].
- *
- * @param model The machine to create.
- */
- public SimVirtualMachine newMachine(MachineModel model) {
- if (!canFit(model)) {
- throw new IllegalArgumentException("Machine does not fit");
- }
-
- SimVirtualMachine vm = new SimVirtualMachine(model);
- vms.add(vm);
- return vm;
- }
-
- /**
- * Remove the specified <code>machine</code> from the hypervisor.
- *
- * @param machine The machine to remove.
- */
- public void removeMachine(SimVirtualMachine machine) {
- if (vms.remove(machine)) {
- // This cast must always succeed, since `_vms` only contains `VirtualMachine` types.
- ((SimVirtualMachine) machine).close();
- }
- }
-
- /**
- * Return the CPU capacity of the hypervisor in MHz.
- */
- public double getCpuCapacity() {
- final SimHyperVisorContext context = activeContext;
-
- if (context == null) {
- return 0.0;
- }
-
- return context.previousCapacity;
- }
-
- /**
- * The CPU demand of the hypervisor in MHz.
- */
- public double getCpuDemand() {
- final SimHyperVisorContext context = activeContext;
-
- if (context == null) {
- return 0.0;
- }
-
- return context.previousDemand;
- }
-
- /**
- * The CPU usage of the hypervisor in MHz.
- */
- public double getCpuUsage() {
- final SimHyperVisorContext context = activeContext;
-
- if (context == null) {
- return 0.0;
- }
-
- return context.previousRate;
- }
-
- /**
- * Determine whether the specified machine characterized by <code>model</code> can fit on this hypervisor at this
- * moment.
- */
- public boolean canFit(MachineModel model) {
- final SimHyperVisorContext context = activeContext;
- if (context == null) {
- return false;
- }
-
- final FlowMultiplexer multiplexer = context.multiplexer;
- return (multiplexer.getMaxInputs() - multiplexer.getInputCount()) >= 1;
- }
-
- @Override
- public void onStart(SimMachineContext ctx) {
- final SimHyperVisorContext context =
- new SimHyperVisorContext(ctx, muxFactory, scalingGovernorFactory, counters);
- context.start();
- activeContext = context;
- }
-
- @Override
- public void onStop(SimMachineContext ctx) {
- final SimHyperVisorContext context = activeContext;
- if (context != null) {
- activeContext = null;
- context.stop();
- }
- }
-
- @Override
- public void makeSnapshot(long now) {
- throw new UnsupportedOperationException("Unable to snapshot hypervisor");
- }
-
- @Override
- public SimWorkload getSnapshot() {
- throw new UnsupportedOperationException("Unable to snapshot hypervisor");
- }
-
- @Override
- public void createCheckpointModel() {
- throw new UnsupportedOperationException("Unable to create a checkpointing system for a hypervisor");
- }
-
- @Override
- public long getCheckpointInterval() {
- return -1;
- }
-
- @Override
- public long getCheckpointDuration() {
- return -1;
- }
-
- @Override
- public double getCheckpointIntervalScaling() {
- return -1;
- }
-
- /**
- * The context which carries the state when the hypervisor is running on a machine.
- */
- private static final class SimHyperVisorContext implements FlowStageLogic {
- private final SimMachineContext ctx;
- private final FlowMultiplexer multiplexer;
- private final FlowStage stage;
- private final ScalingGovernor scalingGovernor;
- private final InstantSource clock;
- private final HvCounters counters;
-
- private long lastCounterUpdate;
- private final double d;
- private float previousDemand;
- private float previousRate;
- private float previousCapacity;
-
- private SimHyperVisorContext(
- SimMachineContext ctx,
- FlowMultiplexerFactory muxFactory,
- ScalingGovernorFactory scalingGovernorFactory,
- HvCounters counters) {
-
- this.ctx = ctx;
- this.counters = counters;
-
- final FlowGraph graph = ctx.getGraph();
- this.multiplexer = muxFactory.newMultiplexer(graph);
- this.stage = graph.newStage(this);
- this.clock = graph.getEngine().getClock();
-
- this.lastCounterUpdate = clock.millis();
-
- final SimProcessingUnit cpu = ctx.getCpu();
-
- if (scalingGovernorFactory != null) {
- this.scalingGovernor = scalingGovernorFactory.newGovernor(new ScalingPolicyImpl(cpu));
- } else {
- this.scalingGovernor = null;
- }
-
- this.d = 1 / cpu.getFrequency();
- }
-
- /**
- * Start the hypervisor on a new machine.
- */
- void start() {
- final FlowGraph graph = ctx.getGraph();
- final FlowMultiplexer multiplexer = this.multiplexer;
-
- graph.connect(multiplexer.newOutput(), ctx.getCpu().getInput());
-
- if (this.scalingGovernor != null) {
- this.scalingGovernor.onStart();
- }
- }
-
- /**
- * Stop the hypervisor.
- */
- void stop() {
- // Synchronize the counters before stopping the hypervisor. Otherwise, the last report is missed.
- updateCounters(clock.millis());
-
- stage.close();
- }
-
- /**
- * Invalidate the {@link FlowStage} of the hypervisor.
- */
- void invalidate() {
- stage.invalidate();
- }
-
- /**
- * Update the performance counters of the hypervisor.
- *
- * @param now The timestamp at which to update the counter.
- */
- void updateCounters(long now) {
- long lastUpdate = this.lastCounterUpdate;
- this.lastCounterUpdate = now;
- long delta = now - lastUpdate;
-
- if (delta > 0) {
- final HvCounters counters = this.counters;
-
- float demand = previousDemand;
- float rate = previousRate;
- float capacity = previousCapacity;
-
- final double factor = this.d * delta;
-
- counters.cpuActiveTime += Math.round(rate * factor);
- counters.cpuIdleTime += Math.round((capacity - rate) * factor);
- counters.cpuStealTime += Math.round((demand - rate) * factor);
- }
- }
-
- /**
- * Update the performance counters of the hypervisor.
- */
- void updateCounters() {
- updateCounters(clock.millis());
- }
-
- @Override
- public long onUpdate(FlowStage ctx, long now) {
- updateCounters(now);
-
- final FlowMultiplexer multiplexer = this.multiplexer;
- final ScalingGovernor scalingGovernors = this.scalingGovernor;
-
- float demand = multiplexer.getDemand();
- float rate = multiplexer.getRate();
- float capacity = multiplexer.getCapacity();
-
- this.previousDemand = demand;
- this.previousRate = rate;
- this.previousCapacity = capacity;
-
- double load = rate / Math.min(1.0, capacity);
-
- if (scalingGovernor != null) {
- scalingGovernor.onLimit(load);
- }
-
- return Long.MAX_VALUE;
- }
- }
-
- /**
- * A {@link ScalingPolicy} for a physical CPU of the hypervisor.
- */
- private static final class ScalingPolicyImpl implements ScalingPolicy {
- private final SimProcessingUnit cpu;
-
- private ScalingPolicyImpl(SimProcessingUnit cpu) {
- this.cpu = cpu;
- }
-
- @Override
- public SimProcessingUnit getCpu() {
- return cpu;
- }
-
- @Override
- public double getTarget() {
- return cpu.getFrequency();
- }
-
- @Override
- public void setTarget(double target) {
- cpu.setFrequency(target);
- }
-
- @Override
- public double getMin() {
- return 0;
- }
-
- @Override
- public double getMax() {
- return cpu.getCpuModel().getTotalCapacity();
- }
- }
-
- /**
- * A virtual machine running on the hypervisor.
- */
- public class SimVirtualMachine extends SimAbstractMachine {
- private boolean isClosed;
- private final VmCounters counters = new VmCounters(this);
-
- private SimVirtualMachine(MachineModel model) {
- super(model);
- }
-
- public SimHypervisorCounters getCounters() {
- return counters;
- }
-
- public double getCpuDemand() {
- final VmContext context = (VmContext) getActiveContext();
-
- if (context == null) {
- return 0.0;
- }
-
- return context.previousDemand;
- }
-
- public double getCpuUsage() {
- final VmContext context = (VmContext) getActiveContext();
-
- if (context == null) {
- return 0.0;
- }
-
- return context.usage;
- }
-
- public double getCpuCapacity() {
- final VmContext context = (VmContext) getActiveContext();
-
- if (context == null) {
- return 0.0;
- }
-
- return context.previousCapacity;
- }
-
- @Override
- public List<? extends SimPeripheral> getPeripherals() {
- return Collections.emptyList();
- }
-
- @Override
- protected SimAbstractMachineContext createContext(
- SimWorkload workload, Map<String, Object> meta, Consumer<Exception> completion) {
- if (isClosed) {
- throw new IllegalStateException("Virtual machine does not exist anymore");
- }
-
- final SimHyperVisorContext context = activeContext;
- if (context == null) {
- throw new IllegalStateException("Hypervisor is inactive");
- }
-
- return new VmContext(
- context,
- this,
- random,
- interferenceDomain,
- counters,
- SimHypervisor.this.counters,
- workload,
- meta,
- completion);
- }
-
- @Override
- public SimAbstractMachineContext getActiveContext() {
- return super.getActiveContext();
- }
-
- void close() {
- if (isClosed) {
- return;
- }
-
- isClosed = true;
- cancel();
- }
- }
-
- /**
- * A {@link SimAbstractMachine.SimAbstractMachineContext} for a virtual machine instance.
- */
- private static final class VmContext extends SimAbstractMachine.SimAbstractMachineContext
- implements FlowStageLogic {
- private final SimHyperVisorContext simHyperVisorContext;
- private final SplittableRandom random;
- private final VmCounters vmCounters;
- private final HvCounters hvCounters;
- private final VmInterferenceMember interferenceMember;
- private final FlowStage stage;
- private final FlowMultiplexer multiplexer;
- private final InstantSource clock;
-
- private final VCpu cpu;
- private final SimAbstractMachine.Memory memory;
- private final List<SimAbstractMachine.NetworkAdapter> net;
- private final List<SimAbstractMachine.StorageDevice> disk;
-
- private final Inlet[] muxInlets;
- private long lastUpdate;
- private long lastCounterUpdate;
- private final double d;
-
- private float demand;
- private float usage;
- private float capacity;
-
- private float previousDemand;
- private float previousCapacity;
-
- private VmContext(
- SimHyperVisorContext simHyperVisorContext,
- SimVirtualMachine machine,
- SplittableRandom random,
- VmInterferenceDomain interferenceDomain,
- VmCounters vmCounters,
- HvCounters hvCounters,
- SimWorkload workload,
- Map<String, Object> meta,
- Consumer<Exception> completion) {
- super(machine, workload, meta, completion);
-
- this.simHyperVisorContext = simHyperVisorContext;
- this.random = random;
- this.vmCounters = vmCounters;
- this.hvCounters = hvCounters;
- this.clock = simHyperVisorContext.clock;
-
- final VmInterferenceProfile interferenceProfile = (VmInterferenceProfile) meta.get("interference-profile");
- VmInterferenceMember interferenceMember = null;
- if (interferenceDomain != null && interferenceProfile != null) {
- interferenceMember = interferenceDomain.join(interferenceProfile);
- interferenceMember.activate();
- }
- this.interferenceMember = interferenceMember;
-
- final FlowGraph graph = simHyperVisorContext.ctx.getGraph();
- final FlowStage stage = graph.newStage(this);
- this.stage = stage;
- this.lastUpdate = clock.millis();
- this.lastCounterUpdate = clock.millis();
-
- final FlowMultiplexer multiplexer = simHyperVisorContext.multiplexer;
- this.multiplexer = multiplexer;
-
- final MachineModel model = machine.getModel();
- final Cpu cpuModel = model.getCpu();
- final Inlet[] muxInlets = new Inlet[1];
-
- this.muxInlets = muxInlets;
-
- final Inlet muxInlet = multiplexer.newInput();
- muxInlets[0] = muxInlet;
-
- final InPort input = stage.getInlet("cpu");
- final OutPort output = stage.getOutlet("mux");
-
- final Handler handler = new Handler(this, input, output);
- input.setHandler(handler);
- output.setHandler(handler);
-
- this.cpu = new VCpu(cpuModel, input);
-
- graph.connect(output, muxInlet);
-
- this.d = 1 / cpuModel.getTotalCapacity();
-
- this.memory = new SimAbstractMachine.Memory(graph, model.getMemory());
-
- int netIndex = 0;
- final ArrayList<SimAbstractMachine.NetworkAdapter> net = new ArrayList<>();
- this.net = net;
- for (org.opendc.simulator.compute.model.NetworkAdapter adapter : model.getNetwork()) {
- net.add(new SimAbstractMachine.NetworkAdapter(graph, adapter, netIndex++));
- }
-
- int diskIndex = 0;
- final ArrayList<SimAbstractMachine.StorageDevice> disk = new ArrayList<>();
- this.disk = disk;
- for (org.opendc.simulator.compute.model.StorageDevice device : model.getStorage()) {
- disk.add(new SimAbstractMachine.StorageDevice(graph, device, diskIndex++));
- }
- }
-
- /**
- * Update the performance counters of the virtual machine.
- *
- * @param now The timestamp at which to update the counter.
- */
- void updateCounters(long now) {
- long lastUpdate = this.lastCounterUpdate;
- this.lastCounterUpdate = now;
- long delta = now - lastUpdate; // time between updates
-
- if (delta > 0) {
- final VmCounters counters = this.vmCounters;
-
- float demand = this.previousDemand;
- float rate = this.usage;
- float capacity = this.previousCapacity;
-
- final double factor = this.d * delta; // time between divided by total capacity
- final double active = rate * factor;
-
- counters.cpuActiveTime += Math.round(active);
- counters.cpuIdleTime += Math.round((capacity - rate) * factor);
- counters.cpuStealTime += Math.round((demand - rate) * factor);
- }
- }
-
- /**
- * Update the performance counters of the virtual machine.
- */
- void updateCounters() {
- updateCounters(clock.millis());
- }
-
- @Override
- public FlowGraph getGraph() {
- return stage.getGraph();
- }
-
- @Override
- public SimProcessingUnit getCpu() {
- return cpu;
- }
-
- @Override
- public SimMemory getMemory() {
- return memory;
- }
-
- @Override
- public List<? extends SimNetworkInterface> getNetworkInterfaces() {
- return net;
- }
-
- @Override
- public List<? extends SimStorageInterface> getStorageInterfaces() {
- return disk;
- }
-
- @Override
- public long onUpdate(FlowStage ctx, long now) {
- float usage = 0.f;
- for (Inlet inlet : muxInlets) {
- usage += ((InPort) inlet).getRate();
- }
- this.usage = usage;
- this.previousDemand = demand;
- this.previousCapacity = capacity;
-
- long lastUpdate = this.lastUpdate;
- this.lastUpdate = now;
- long delta = now - lastUpdate;
-
- if (delta > 0) {
- final VmInterferenceMember interferenceMember = this.interferenceMember;
- double penalty = 0.0;
-
- if (interferenceMember != null) {
- final FlowMultiplexer multiplexer = this.multiplexer;
- double load = multiplexer.getRate() / Math.min(1.0, multiplexer.getCapacity());
- penalty = 1 - interferenceMember.apply(random, load);
- }
-
- final double factor = this.d * delta;
- final long lostTime = Math.round(factor * usage * penalty);
-
- this.vmCounters.cpuLostTime += lostTime;
- this.hvCounters.cpuLostTime += lostTime;
- }
-
- // Invalidate the FlowStage of the hypervisor to update its counters (via onUpdate)
- simHyperVisorContext.invalidate();
-
- return Long.MAX_VALUE;
- }
-
- @Override
- protected void doCancel() {
- super.doCancel();
-
- // Synchronize the counters before stopping the hypervisor. Otherwise, the last report is missed.
- updateCounters(clock.millis());
-
- stage.close();
-
- final FlowMultiplexer multiplexer = this.multiplexer;
- for (Inlet muxInlet : muxInlets) {
- multiplexer.releaseInput(muxInlet);
- }
-
- final VmInterferenceMember interferenceMember = this.interferenceMember;
- if (interferenceMember != null) {
- interferenceMember.deactivate();
- }
- }
- }
-
- /**
- * A {@link SimProcessingUnit} of a virtual machine.
- */
- private static final class VCpu implements SimProcessingUnit {
- private final Cpu model;
- private final InPort input;
-
- private VCpu(Cpu model, InPort input) {
- this.model = model;
- this.input = input;
-
- input.pull((float) model.getTotalCapacity());
- }
-
- @Override
- public double getFrequency() {
- return input.getCapacity();
- }
-
- @Override
- public void setFrequency(double frequency) {
- input.pull((float) frequency);
- }
-
- @Override
- public double getDemand() {
- return input.getDemand();
- }
-
- @Override
- public double getSpeed() {
- return input.getRate();
- }
-
- @Override
- public Cpu getCpuModel() {
- return model;
- }
-
- @Override
- public Inlet getInput() {
- return input;
- }
-
- @Override
- public String toString() {
- return "SimHypervisor.VCpu[model" + model + "]";
- }
- }
-
- /**
- * A handler for forwarding flow between an inlet and outlet.
- */
- private static class Handler implements InHandler, OutHandler {
- private final InPort input;
- private final OutPort output;
- private final VmContext context;
-
- private Handler(VmContext context, InPort input, OutPort output) {
- this.context = context;
- this.input = input;
- this.output = output;
- }
-
- @Override
- public void onPush(InPort port, float demand) {
- context.demand += -port.getDemand() + demand;
-
- output.push(demand);
- }
-
- @Override
- public void onUpstreamFinish(InPort port, Throwable cause) {
- context.demand -= port.getDemand();
-
- output.push(0.f);
- }
-
- @Override
- public float getRate(InPort port) {
- return output.getRate();
- }
-
- @Override
- public void onPull(OutPort port, float capacity) {
- context.capacity += -port.getCapacity() + capacity;
-
- input.pull(capacity);
- }
-
- @Override
- public void onDownstreamFinish(OutPort port, Throwable cause) {
- context.capacity -= port.getCapacity();
-
- input.pull(0.f);
- }
- }
-
- /**
- * Implementation of {@link SimHypervisorCounters} for the hypervisor.
- */
- private class HvCounters implements SimHypervisorCounters {
- private long cpuActiveTime;
- private long cpuIdleTime;
- private long cpuStealTime;
- private long cpuLostTime;
-
- @Override
- public long getCpuActiveTime() {
- return cpuActiveTime;
- }
-
- @Override
- public long getCpuIdleTime() {
- return cpuIdleTime;
- }
-
- @Override
- public long getCpuStealTime() {
- return cpuStealTime;
- }
-
- @Override
- public long getCpuLostTime() {
- return cpuLostTime;
- }
-
- @Override
- public void sync() {
- final SimHyperVisorContext context = activeContext;
-
- if (context != null) {
- context.updateCounters();
- }
- }
- }
-
- /**
- * Implementation of {@link SimHypervisorCounters} for the virtual machine.
- */
- private static class VmCounters implements SimHypervisorCounters {
- private final SimVirtualMachine vm;
- private long cpuActiveTime;
- private long cpuIdleTime;
- private long cpuStealTime;
- private long cpuLostTime;
-
- private VmCounters(SimVirtualMachine vm) {
- this.vm = vm;
- }
-
- @Override
- public long getCpuActiveTime() {
- return cpuActiveTime;
- }
-
- @Override
- public long getCpuIdleTime() {
- return cpuIdleTime;
- }
-
- @Override
- public long getCpuStealTime() {
- return cpuStealTime;
- }
-
- @Override
- public long getCpuLostTime() {
- return cpuLostTime;
- }
-
- @Override
- public void sync() {
- final VmContext context = (VmContext) vm.getActiveContext();
-
- if (context != null) {
- context.updateCounters();
- }
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/SimHypervisorCounters.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/SimHypervisorCounters.java
deleted file mode 100644
index fc77e9d6..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/SimHypervisorCounters.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2022 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.kernel;
-
-/**
- * Performance counters of a {@link SimHypervisor}.
- */
-public interface SimHypervisorCounters {
- /**
- * Return the amount of time (in milliseconds) the CPUs of the hypervisor were actively running.
- */
- long getCpuActiveTime();
-
- /**
- * Return the amount of time (in milliseconds) the CPUs of the hypervisor were idle.
- */
- long getCpuIdleTime();
-
- /**
- * Return the amount of CPU time (in milliseconds) that virtual machines were ready to run, but were not able to.
- */
- long getCpuStealTime();
-
- /**
- * Return the amount of CPU time (in milliseconds) that was lost due to interference between virtual machines.
- */
- long getCpuLostTime();
-
- /**
- * Synchronize the counter values.
- */
- void sync();
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/cpufreq/ScalingGovernor.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/cpufreq/ScalingGovernor.java
deleted file mode 100644
index 69a371e1..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/cpufreq/ScalingGovernor.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2022 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.kernel.cpufreq;
-
-/**
- * A [ScalingGovernor] in the CPUFreq subsystem of OpenDC is responsible for scaling the frequency of simulated CPUs
- * independent of the particular implementation of the CPU.
- *
- * <p>
- * Each of the scaling governors implements a single, possibly parametrized, performance scaling algorithm.
- *
- * @see <a href="https://www.kernel.org/doc/html/latest/admin-guide/pm/cpufreq.html">documentation of the Linux CPUFreq subsystem</a>.
- */
-public interface ScalingGovernor {
- /**
- * This method is invoked when the governor is started.
- */
- default void onStart() {}
-
- /**
- * This method is invoked when the governor should re-decide the frequency limits.
- *
- * @param load The load of the system.
- */
- default void onLimit(double load) {}
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/cpufreq/ScalingGovernorFactory.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/cpufreq/ScalingGovernorFactory.java
deleted file mode 100644
index 97a49879..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/cpufreq/ScalingGovernorFactory.java
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (c) 2022 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.kernel.cpufreq;
-
-/**
- * Factory interface for a {@link ScalingGovernor}.
- */
-public interface ScalingGovernorFactory {
- /**
- * Create the scaling logic for the specified {@link ScalingPolicy}.
- */
- ScalingGovernor newGovernor(ScalingPolicy policy);
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/cpufreq/ScalingGovernors.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/cpufreq/ScalingGovernors.java
deleted file mode 100644
index 2b10ae59..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/cpufreq/ScalingGovernors.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright (c) 2022 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.kernel.cpufreq;
-
-/**
- * Collection of common {@link ScalingGovernor} implementations.
- */
-public class ScalingGovernors {
- private ScalingGovernors() {}
-
- /**
- * Return a {@link ScalingGovernorFactory} for the <code>performance</code> scaling governor.
- *
- * <p>
- * This governor causes the highest possible frequency to be requested from the CPUs.
- */
- public static ScalingGovernorFactory performance() {
- return PerformanceScalingGovernor.FACTORY;
- }
-
- /**
- * Return a {@link ScalingGovernorFactory} for the <code>powersave</code> scaling governor.
- *
- * <p>
- * This governor causes the lowest possible frequency to be requested from the CPUs.
- */
- public static ScalingGovernorFactory powerSave() {
- return PowerSaveScalingGovernor.FACTORY;
- }
-
- /**
- * Return a {@link ScalingGovernorFactory} for the <code>conservative</code> scaling governor from the Linux kernel.
- *
- * @param threshold The threshold before scaling.
- * @param stepSize The size of the frequency steps (use negative value for automatic).
- */
- public static ScalingGovernorFactory conservative(double threshold, double stepSize) {
- return (policy) -> new ConservativeScalingGovernor(policy, threshold, stepSize);
- }
-
- /**
- * Return a {@link ScalingGovernorFactory} for the <code>conservative</code> scaling governor from the Linux kernel.
- *
- * @param threshold The threshold before scaling.
- */
- public static ScalingGovernorFactory conservative(double threshold) {
- return conservative(threshold, -1.0);
- }
-
- /**
- * Return a {@link ScalingGovernorFactory} for the <code>ondemand</code> scaling governor from the Linux kernel.
- *
- * @param threshold The threshold before scaling.
- */
- public static ScalingGovernorFactory ondemand(double threshold) {
- return (policy) -> new OnDemandScalingGovernor(policy, threshold);
- }
-
- private abstract static class AbstractScalingGovernor implements ScalingGovernor {
- protected final ScalingPolicy policy;
-
- AbstractScalingGovernor(ScalingPolicy policy) {
- this.policy = policy;
- }
- }
-
- private static class PerformanceScalingGovernor extends AbstractScalingGovernor {
- static final ScalingGovernorFactory FACTORY = PerformanceScalingGovernor::new;
-
- private PerformanceScalingGovernor(ScalingPolicy policy) {
- super(policy);
- }
-
- @Override
- public void onStart() {
- policy.setTarget(policy.getMax());
- }
- }
-
- private static class PowerSaveScalingGovernor extends AbstractScalingGovernor {
- static final ScalingGovernorFactory FACTORY = PowerSaveScalingGovernor::new;
-
- private PowerSaveScalingGovernor(ScalingPolicy policy) {
- super(policy);
- }
-
- @Override
- public void onStart() {
- policy.setTarget(policy.getMin());
- }
- }
-
- private static class ConservativeScalingGovernor extends AbstractScalingGovernor {
- private final double threshold;
- private final double stepSize;
- private double previousLoad;
-
- private ConservativeScalingGovernor(ScalingPolicy policy, double threshold, double stepSize) {
- super(policy);
-
- this.threshold = threshold;
- this.previousLoad = threshold;
-
- if (stepSize < 0) {
- // https://github.com/torvalds/linux/blob/master/drivers/cpufreq/cpufreq_conservative.c#L33
- this.stepSize = policy.getMax() * 0.05;
- } else {
- this.stepSize = Math.min(stepSize, policy.getMax());
- }
- }
-
- @Override
- public void onStart() {
- policy.setTarget(policy.getMin());
- }
-
- @Override
- public void onLimit(double load) {
- final ScalingPolicy policy = this.policy;
- double currentTarget = policy.getTarget();
- if (load > threshold) {
- // Check for load increase (see:
- // https://github.com/torvalds/linux/blob/master/drivers/cpufreq/cpufreq_conservative.c#L102)
- double step = 0.0;
-
- if (load > previousLoad) {
- step = stepSize;
- } else if (load < previousLoad) {
- step = -stepSize;
- }
-
- double target = Math.min(Math.max(currentTarget + step, policy.getMin()), policy.getMax());
- policy.setTarget(target);
- }
- previousLoad = load;
- }
- }
-
- private static class OnDemandScalingGovernor extends AbstractScalingGovernor {
- private final double threshold;
- private final double multiplier;
-
- private OnDemandScalingGovernor(ScalingPolicy policy, double threshold) {
- super(policy);
-
- this.threshold = threshold;
- this.multiplier = (policy.getMax() - policy.getMin()) / 100;
- }
-
- @Override
- public void onStart() {
- policy.setTarget(policy.getMin());
- }
-
- @Override
- public void onLimit(double load) {
- final ScalingPolicy policy = this.policy;
- double target;
-
- if (load < threshold) {
- /* Proportional scaling (see: https://github.com/torvalds/linux/blob/master/drivers/cpufreq/cpufreq_ondemand.c#L151). */
- target = policy.getMin() + load * multiplier;
- } else {
- target = policy.getMax();
- }
-
- policy.setTarget(target);
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/cpufreq/ScalingPolicy.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/cpufreq/ScalingPolicy.java
deleted file mode 100644
index 0cdb7a0b..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/cpufreq/ScalingPolicy.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2022 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.kernel.cpufreq;
-
-import org.opendc.simulator.compute.SimProcessingUnit;
-
-/**
- * An interface that holds the state managed by a {@link ScalingGovernor} and used by the underlying machine to control
- * the CPU frequencies.
- */
-public interface ScalingPolicy {
- /**
- * The processing unit that is associated with this policy.
- */
- SimProcessingUnit getCpu();
-
- /**
- * Return the target frequency which the CPU should attempt to attain.
- */
- double getTarget();
-
- /**
- * Set the target frequency which the CPU should attempt to attain.
- */
- void setTarget(double target);
-
- /**
- * Return the minimum frequency to which the CPU may scale.
- */
- double getMin();
-
- /**
- * Return the maximum frequency to which the CPU may scale.
- */
- double getMax();
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/interference/VmInterferenceDomain.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/interference/VmInterferenceDomain.java
deleted file mode 100644
index cc671379..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/interference/VmInterferenceDomain.java
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright (c) 2022 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.kernel.interference;
-
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.WeakHashMap;
-
-/**
- * A domain where virtual machines may incur performance variability due to operating on the same resource and
- * therefore causing interference.
- */
-public final class VmInterferenceDomain {
- /**
- * A cache to maintain a mapping between the active profiles in this domain.
- */
- private final WeakHashMap<VmInterferenceProfile, VmInterferenceMember> cache = new WeakHashMap<>();
-
- /**
- * The set of members active in this domain.
- */
- private final ArrayList<VmInterferenceMember> activeKeys = new ArrayList<>();
-
- /**
- * Queue of participants that will be removed or added to the active groups.
- */
- private final ArrayDeque<VmInterferenceMember> participants = new ArrayDeque<>();
-
- /**
- * Join this interference domain with the specified <code>profile</code> and return the {@link VmInterferenceMember}
- * associated with the profile. If the member does not exist, it will be created.
- */
- public VmInterferenceMember join(VmInterferenceProfile profile) {
- return cache.computeIfAbsent(profile, (key) -> key.newMember(this));
- }
-
- /**
- * Mark the specified <code>member</code> as active in this interference domain.
- */
- void activate(VmInterferenceMember member) {
- final ArrayList<VmInterferenceMember> activeKeys = this.activeKeys;
- int pos = Collections.binarySearch(activeKeys, member);
- if (pos < 0) {
- activeKeys.add(-pos - 1, member);
- }
-
- computeActiveGroups(activeKeys, member);
- }
-
- /**
- * Mark the specified <code>member</code> as inactive in this interference domain.
- */
- void deactivate(VmInterferenceMember member) {
- final ArrayList<VmInterferenceMember> activeKeys = this.activeKeys;
- activeKeys.remove(member);
- computeActiveGroups(activeKeys, member);
- }
-
- /**
- * (Re-)compute the active groups.
- */
- private void computeActiveGroups(ArrayList<VmInterferenceMember> activeKeys, VmInterferenceMember member) {
- if (activeKeys.isEmpty()) {
- return;
- }
-
- final int[] groups = member.membership;
- final int[][] members = member.members;
- final ArrayDeque<VmInterferenceMember> participants = this.participants;
-
- for (int group : groups) {
- int[] groupMembers = members[group];
-
- int i = 0;
- int j = 0;
- int intersection = 0;
-
- // Compute the intersection of the group members and the current active members
- while (i < groupMembers.length && j < activeKeys.size()) {
- int l = groupMembers[i];
- final VmInterferenceMember rightEntry = activeKeys.get(j);
- int r = rightEntry.id;
-
- if (l < r) {
- i++;
- } else if (l > r) {
- j++;
- } else {
- if (++intersection > 1) {
- rightEntry.addGroup(group);
- } else {
- participants.add(rightEntry);
- }
-
- i++;
- j++;
- }
- }
-
- while (true) {
- VmInterferenceMember participant = participants.poll();
-
- if (participant == null) {
- break;
- }
-
- if (intersection <= 1) {
- participant.removeGroup(group);
- } else {
- participant.addGroup(group);
- }
- }
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/interference/VmInterferenceMember.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/interference/VmInterferenceMember.java
deleted file mode 100644
index 64cd5077..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/interference/VmInterferenceMember.java
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright (c) 2022 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.kernel.interference;
-
-import java.util.Arrays;
-import java.util.SplittableRandom;
-import org.jetbrains.annotations.NotNull;
-
-/**
- * A participant of an interference domain.
- */
-public final class VmInterferenceMember implements Comparable<VmInterferenceMember> {
- private final VmInterferenceDomain domain;
- private final VmInterferenceModel model;
- final int id;
- final int[] membership;
- final int[][] members;
- private final double[] targets;
- private final double[] scores;
-
- private int[] groups = new int[2];
- private int groupsSize = 0;
-
- private int refCount = 0;
-
- VmInterferenceMember(
- VmInterferenceDomain domain,
- VmInterferenceModel model,
- int id,
- int[] membership,
- int[][] members,
- double[] targets,
- double[] scores) {
- this.domain = domain;
- this.model = model;
- this.id = id;
- this.membership = membership;
- this.members = members;
- this.targets = targets;
- this.scores = scores;
- }
-
- /**
- * Mark this member as active in this interference domain.
- */
- public void activate() {
- if (refCount++ <= 0) {
- domain.activate(this);
- }
- }
-
- /**
- * Mark this member as inactive in this interference domain.
- */
- public void deactivate() {
- if (--refCount <= 0) {
- domain.deactivate(this);
- }
- }
-
- /**
- * Compute the performance score of the member in this interference domain.
- *
- * @param random The source of randomness to apply when computing the performance score.
- * @param load The overall load on the interference domain.
- * @return A score representing the performance score to be applied to the member, with 1
- * meaning no influence, <1 means that performance degrades, and >1 means that performance improves.
- */
- public double apply(SplittableRandom random, double load) {
- int groupsSize = this.groupsSize;
-
- if (groupsSize == 0) {
- return 1.0;
- }
-
- int[] groups = this.groups;
- double[] targets = this.targets;
-
- int low = 0;
- int high = groupsSize - 1;
- int group = -1;
-
- // Perform binary search over the groups based on target load
- while (low <= high) {
- int mid = low + high >>> 1;
- int midGroup = groups[mid];
- double target = targets[midGroup];
-
- if (target < load) {
- low = mid + 1;
- group = midGroup;
- } else if (target > load) {
- high = mid - 1;
- } else {
- group = midGroup;
- break;
- }
- }
-
- if (group >= 0 && random.nextInt(members[group].length) == 0) {
- return scores[group];
- }
-
- return 1.0;
- }
-
- /**
- * Add an active group to this member.
- */
- void addGroup(int group) {
- int[] groups = this.groups;
- int groupsSize = this.groupsSize;
- int pos = Arrays.binarySearch(groups, 0, groupsSize, group);
-
- if (pos >= 0) {
- return;
- }
-
- int idx = -pos - 1;
-
- if (groups.length == groupsSize) {
- int newSize = groupsSize + (groupsSize >> 1);
- groups = Arrays.copyOf(groups, newSize);
- this.groups = groups;
- }
-
- System.arraycopy(groups, idx, groups, idx + 1, groupsSize - idx);
- groups[idx] = group;
- this.groupsSize += 1;
- }
-
- /**
- * Remove an active group from this member.
- */
- void removeGroup(int group) {
- int[] groups = this.groups;
- int groupsSize = this.groupsSize;
- int pos = Arrays.binarySearch(groups, 0, groupsSize, group);
-
- if (pos < 0) {
- return;
- }
-
- System.arraycopy(groups, pos + 1, groups, pos, groupsSize - pos - 1);
- this.groupsSize -= 1;
- }
-
- @Override
- public int compareTo(@NotNull VmInterferenceMember member) {
- int cmp = Integer.compare(model.hashCode(), member.model.hashCode());
- if (cmp != 0) {
- return cmp;
- }
-
- return Integer.compare(id, member.id);
- }
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/interference/VmInterferenceModel.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/interference/VmInterferenceModel.java
deleted file mode 100644
index e2093266..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/interference/VmInterferenceModel.java
+++ /dev/null
@@ -1,185 +0,0 @@
-/*
- * Copyright (c) 2022 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.kernel.interference;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.TreeMap;
-import java.util.TreeSet;
-import org.jetbrains.annotations.Nullable;
-
-/**
- * An interference model that models the resource interference between virtual machines on a host.
- */
-public final class VmInterferenceModel {
- private final Map<String, Integer> idMapping;
- private final int[][] members;
- private final int[][] membership;
- private final double[] targets;
- private final double[] scores;
-
- private VmInterferenceModel(
- Map<String, Integer> idMapping, int[][] members, int[][] membership, double[] targets, double[] scores) {
- this.idMapping = idMapping;
- this.members = members;
- this.membership = membership;
- this.targets = targets;
- this.scores = scores;
- }
-
- /**
- * Create a {@link Builder} for constructing a {@link VmInterferenceModel}.
- */
- public static Builder builder() {
- return new Builder(256);
- }
-
- /**
- * Return the {@link VmInterferenceProfile} associated with the specified <code>id</code>.
- *
- * @param id The identifier of the virtual machine.
- * @return A {@link VmInterferenceProfile} representing the virtual machine as part of interference model or
- * <code>null</code> if there is no profile for the virtual machine.
- */
- @Nullable
- public VmInterferenceProfile getProfile(String id) {
- Integer intId = idMapping.get(id);
- if (intId == null) {
- return null;
- }
- return new VmInterferenceProfile(this, intId, membership[intId], members, targets, scores);
- }
-
- /**
- * Builder class for a {@link VmInterferenceModel}.
- */
- public static final class Builder {
- private double[] targets;
- private double[] scores;
- private final ArrayList<Set<String>> members;
- private final TreeSet<String> ids;
- private int size;
-
- private Builder(int initialCapacity) {
- this.targets = new double[initialCapacity];
- this.scores = new double[initialCapacity];
- this.members = new ArrayList<>(initialCapacity);
- this.ids = new TreeSet<>();
- }
-
- /**
- * Add the specified group to the model.
- */
- public Builder addGroup(Set<String> members, double targetLoad, double score) {
- int size = this.size;
-
- if (size == targets.length) {
- grow();
- }
-
- targets[size] = targetLoad;
- scores[size] = score;
- this.members.add(members);
- ids.addAll(members);
-
- this.size++;
-
- return this;
- }
-
- /**
- * Build the {@link VmInterferenceModel}.
- */
- public VmInterferenceModel build() {
- int size = this.size;
- double[] targets = this.targets;
- double[] scores = this.scores;
- ArrayList<Set<String>> members = this.members;
-
- Integer[] indices = new Integer[size];
- Arrays.setAll(indices, (i) -> i);
- Arrays.sort(
- indices,
- Comparator.comparingDouble((Integer l) -> targets[l])
- .thenComparingDouble(l -> scores[l])
- .thenComparingInt(l -> l));
-
- double[] newTargets = new double[size];
- double[] newScores = new double[size];
- int[][] newMembers = new int[size][];
-
- int nextId = 0;
-
- Map<String, Integer> idMapping = new HashMap<>();
- TreeMap<String, ArrayList<Integer>> membership = new TreeMap<>();
- for (String id : ids) {
- idMapping.put(id, nextId++);
- membership.put(id, new ArrayList<>());
- }
-
- for (int group = 0; group < indices.length; group++) {
- int j = indices[group];
- newTargets[group] = targets[j];
- newScores[group] = scores[j];
-
- Set<String> groupMembers = members.get(j);
- int[] newGroupMembers = new int[groupMembers.size()];
- int k = 0;
-
- for (String groupMember : groupMembers) {
- newGroupMembers[k++] = idMapping.get(groupMember);
- }
-
- Arrays.sort(newGroupMembers);
- newMembers[group] = newGroupMembers;
-
- for (String member : groupMembers) {
- membership.get(member).add(group);
- }
- }
-
- int[][] newMembership = new int[membership.size()][];
- int k = 0;
- for (ArrayList<Integer> value : membership.values()) {
- newMembership[k++] = value.stream().mapToInt(i -> i).toArray();
- }
-
- return new VmInterferenceModel(idMapping, newMembers, newMembership, newTargets, newScores);
- }
-
- /**
- * Helper function to grow the capacity of the internal arrays.
- */
- private void grow() {
- int oldSize = targets.length;
- int newSize = oldSize + (oldSize >> 1);
-
- targets = Arrays.copyOf(targets, newSize);
- scores = Arrays.copyOf(scores, newSize);
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/interference/VmInterferenceProfile.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/interference/VmInterferenceProfile.java
deleted file mode 100644
index 3f0c0a88..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/interference/VmInterferenceProfile.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 2022 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.kernel.interference;
-
-/**
- * A profile of a particular virtual machine describing its interference pattern with other virtual machines.
- */
-public final class VmInterferenceProfile {
- private final VmInterferenceModel model;
- private final int id;
- private final int[] membership;
- private final int[][] members;
- private final double[] targets;
- private final double[] scores;
-
- /**
- * Construct a {@link VmInterferenceProfile}.
- */
- VmInterferenceProfile(
- VmInterferenceModel model, int id, int[] membership, int[][] members, double[] targets, double[] scores) {
- this.model = model;
- this.id = id;
- this.membership = membership;
- this.members = members;
- this.targets = targets;
- this.scores = scores;
- }
-
- /**
- * Create a new {@link VmInterferenceMember} based on this profile for the specified <code>domain</code>.
- */
- VmInterferenceMember newMember(VmInterferenceDomain domain) {
- return new VmInterferenceMember(domain, model, id, membership, members, targets, scores);
- }
-
- @Override
- public String toString() {
- return "VmInterferenceProfile[id=" + id + "]";
- }
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/machine/PerformanceCounters.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/machine/PerformanceCounters.java
new file mode 100644
index 00000000..b1e30e5c
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/machine/PerformanceCounters.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2024 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package org.opendc.simulator.compute.machine;
+
+public class PerformanceCounters {
+ private long cpuActiveTime = 0;
+ private long cpuIdleTime = 0;
+ private long cpuStealTime = 0;
+ private long cpuLostTime = 0;
+
+ private float cpuCapacity = 0.0f;
+ private float cpuDemand = 0.0f;
+ private float cpuSupply = 0.0f;
+
+ public long getCpuActiveTime() {
+ return cpuActiveTime;
+ }
+
+ public void setCpuActiveTime(long cpuActiveTime) {
+ this.cpuActiveTime = cpuActiveTime;
+ }
+
+ public void addCpuActiveTime(long cpuActiveTime) {
+ this.cpuActiveTime += cpuActiveTime;
+ }
+
+ public long getCpuIdleTime() {
+ return cpuIdleTime;
+ }
+
+ public void setCpuIdleTime(long cpuIdleTime) {
+ this.cpuIdleTime = cpuIdleTime;
+ }
+
+ public void addCpuIdleTime(long cpuIdleTime) {
+ this.cpuIdleTime += cpuIdleTime;
+ }
+
+ public long getCpuStealTime() {
+ return cpuStealTime;
+ }
+
+ public void setCpuStealTime(long cpuStealTime) {
+ this.cpuStealTime = cpuStealTime;
+ }
+
+ public void addCpuStealTime(long cpuStealTime) {
+ this.cpuStealTime += cpuStealTime;
+ }
+
+ public long getCpuLostTime() {
+ return cpuLostTime;
+ }
+
+ public void setCpuLostTime(long cpuLostTime) {
+ this.cpuLostTime = cpuLostTime;
+ }
+
+ public float getCpuCapacity() {
+ return cpuCapacity;
+ }
+
+ public void setCpuCapacity(float cpuCapacity) {
+ this.cpuCapacity = cpuCapacity;
+ }
+
+ public float getCpuDemand() {
+ return cpuDemand;
+ }
+
+ public void setCpuDemand(float cpuDemand) {
+ this.cpuDemand = cpuDemand;
+ }
+
+ public float getCpuSupply() {
+ return cpuSupply;
+ }
+
+ public void setCpuSupply(float cpuSupply) {
+ this.cpuSupply = cpuSupply;
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/machine/SimMachine.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/machine/SimMachine.java
new file mode 100644
index 00000000..00a69efe
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/machine/SimMachine.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2024 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package org.opendc.simulator.compute.machine;
+
+import java.time.InstantSource;
+import java.util.function.Consumer;
+import org.opendc.simulator.Multiplexer;
+import org.opendc.simulator.compute.cpu.CpuPowerModel;
+import org.opendc.simulator.compute.cpu.SimCpu;
+import org.opendc.simulator.compute.memory.Memory;
+import org.opendc.simulator.compute.models.MachineModel;
+import org.opendc.simulator.compute.power.SimPsu;
+import org.opendc.simulator.compute.workload.SimWorkload;
+import org.opendc.simulator.compute.workload.Workload;
+import org.opendc.simulator.engine.FlowGraph;
+
+/**
+ * A machine that is able to execute {@link SimWorkload} objects.
+ */
+public class SimMachine {
+ private final MachineModel machineModel;
+ private final FlowGraph graph;
+
+ private final InstantSource clock;
+
+ private SimCpu cpu;
+ private Multiplexer cpuMux;
+ private SimPsu psu;
+ private Memory memory;
+
+ private Consumer<Exception> completion;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Basic Getters and Setters
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ public PerformanceCounters getPerformanceCounters() {
+ return this.cpu.getPerformanceCounters();
+ }
+
+ public MachineModel getMachineModel() {
+ return machineModel;
+ }
+
+ public FlowGraph getGraph() {
+ return graph;
+ }
+
+ public InstantSource getClock() {
+ return clock;
+ }
+
+ public SimCpu getCpu() {
+ return cpu;
+ }
+
+ public Multiplexer getCpuMux() {
+ return cpuMux;
+ }
+
+ public Memory getMemory() {
+ return memory;
+ }
+
+ public SimPsu getPsu() {
+ return psu;
+ }
+
+ /**
+ * Return the CPU capacity of the hypervisor in MHz.
+ */
+ public double getCpuCapacity() {
+ return 0.0;
+ }
+
+ /**
+ * The CPU demand of the hypervisor in MHz.
+ */
+ public double getCpuDemand() {
+ return 0.0;
+ }
+
+ /**
+ * The CPU usage of the hypervisor in MHz.
+ */
+ public double getCpuUsage() {
+ return 0.0;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Constructors
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ public SimMachine(
+ FlowGraph graph, MachineModel machineModel, CpuPowerModel cpuPowerModel, Consumer<Exception> completion) {
+ this.graph = graph;
+ this.machineModel = machineModel;
+ this.clock = graph.getEngine().getClock();
+
+ // Create the psu and cpu and connect them
+ this.psu = new SimPsu(graph);
+ this.cpu = new SimCpu(graph, this.machineModel.getCpu(), 0);
+
+ graph.addEdge(this.cpu, this.psu);
+
+ this.memory = new Memory(graph, this.machineModel.getMemory());
+
+ // Create a Multiplexer and add the cpu as supplier
+ this.cpuMux = new Multiplexer(this.graph);
+ graph.addEdge(this.cpuMux, this.cpu);
+
+ this.completion = completion;
+ }
+
+ public void shutdown() {
+ shutdown(null);
+ }
+
+ /**
+ * Close all related hardware
+ */
+ public void shutdown(Exception cause) {
+ this.graph.removeNode(this.psu);
+ this.psu = null;
+
+ this.graph.removeNode(this.cpu);
+ this.cpu = null;
+
+ this.graph.removeNode(this.cpuMux);
+ this.cpuMux = null;
+
+ this.memory = null;
+
+ this.completion.accept(cause);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Workload related functionality
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Determine whether the specified machine characterized by <code>model</code> can fit on this hypervisor at this
+ * moment.
+ * TODO: This currently alwasy returns True, maybe remove?
+ */
+ public boolean canFit(MachineModel model) {
+ return true;
+ }
+
+ /**
+ * Create a Virtual Machine, and start the given workload on it.
+ *
+ * @param workload
+ * @param completion
+ * @return
+ */
+ public VirtualMachine startWorkload(Workload workload, Consumer<Exception> completion) {
+ final VirtualMachine vm = new VirtualMachine(this);
+
+ vm.startWorkload(workload, completion);
+
+ return vm;
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/machine/VirtualMachine.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/machine/VirtualMachine.java
new file mode 100644
index 00000000..3bc3d2b4
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/machine/VirtualMachine.java
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2024 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package org.opendc.simulator.compute.machine;
+
+import java.util.function.Consumer;
+import org.opendc.simulator.compute.cpu.SimCpu;
+import org.opendc.simulator.compute.workload.SimWorkload;
+import org.opendc.simulator.compute.workload.Workload;
+import org.opendc.simulator.engine.FlowConsumer;
+import org.opendc.simulator.engine.FlowEdge;
+import org.opendc.simulator.engine.FlowGraph;
+import org.opendc.simulator.engine.FlowNode;
+import org.opendc.simulator.engine.FlowSupplier;
+
+/*
+ A virtual Machine created to run a single workload
+*/
+public class VirtualMachine extends FlowNode implements FlowConsumer, FlowSupplier {
+ private SimMachine machine;
+
+ private SimWorkload activeWorkload;
+
+ private long lastUpdate;
+ private final double d;
+
+ private FlowEdge cpuEdge; // The edge to the cpu
+ private FlowEdge workloadEdge; // The edge to the workload
+
+ private float cpuDemand;
+ private float cpuSupply;
+ private float cpuCapacity;
+
+ private PerformanceCounters performanceCounters = new PerformanceCounters();
+
+ private Consumer<Exception> completion;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Basic Getters and Setters
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ public PerformanceCounters getPerformanceCounters() {
+ return performanceCounters;
+ }
+
+ public SimWorkload getActiveWorkload() {
+ return activeWorkload;
+ }
+
+ public float getDemand() {
+ return cpuDemand;
+ }
+
+ public void setDemand(float demand) {
+ this.cpuDemand = demand;
+ }
+
+ public float getCpuCapacity() {
+ return cpuCapacity;
+ }
+
+ public void setCpuCapacity(float cpuCapacity) {
+ this.cpuCapacity = cpuCapacity;
+ }
+
+ public FlowGraph getGraph() {
+ return this.parentGraph;
+ }
+
+ public SimCpu getCpu() {
+ return machine.getCpu();
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Constructors
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ public VirtualMachine(SimMachine machine) {
+ super(machine.getGraph());
+ this.machine = machine;
+ this.clock = this.machine.getClock();
+
+ this.parentGraph = machine.getGraph();
+ this.parentGraph.addEdge(this, this.machine.getCpuMux());
+
+ this.lastUpdate = clock.millis();
+ this.lastUpdate = clock.millis();
+
+ this.d = 1 / machine.getCpu().getFrequency();
+ }
+
+ public void shutdown() {
+ this.shutdown(null);
+ }
+
+ public void shutdown(Exception cause) {
+ if (this.nodeState == NodeState.CLOSED) {
+ return;
+ }
+
+ super.closeNode();
+
+ this.activeWorkload = null;
+ this.performanceCounters = null;
+
+ this.completion.accept(cause);
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Workload related functionality
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ public void startWorkload(Workload workload, Consumer<Exception> completion) {
+ this.completion = completion;
+ this.activeWorkload = workload.startWorkload(this, this.clock.millis());
+ }
+
+ public void updateCounters(long now) {
+ long lastUpdate = this.lastUpdate;
+ this.lastUpdate = now;
+ long delta = now - lastUpdate;
+
+ if (delta > 0) {
+ final double factor = this.d * delta;
+
+ this.performanceCounters.addCpuActiveTime(Math.round(this.cpuSupply * factor));
+ this.performanceCounters.setCpuIdleTime(Math.round((this.cpuCapacity - this.cpuSupply) * factor));
+ this.performanceCounters.addCpuStealTime(Math.round((this.cpuDemand - this.cpuSupply) * factor));
+ }
+
+ this.performanceCounters.setCpuDemand(this.cpuDemand);
+ this.performanceCounters.setCpuSupply(this.cpuSupply);
+ this.performanceCounters.setCpuCapacity(this.cpuCapacity);
+ }
+
+ @Override
+ public long onUpdate(long now) {
+ updateCounters(now);
+
+ return Long.MAX_VALUE;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // FlowGraph Related functionality
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Add an edge to the workload
+ * TODO: maybe add a check if there is already an edge
+ */
+ @Override
+ public void addConsumerEdge(FlowEdge consumerEdge) {
+ this.workloadEdge = consumerEdge;
+ }
+
+ /**
+ * Add an edge to the cpuMux
+ * TODO: maybe add a check if there is already an edge
+ */
+ @Override
+ public void addSupplierEdge(FlowEdge supplierEdge) {
+ this.cpuEdge = supplierEdge;
+ }
+
+ /**
+ * Push demand to the cpuMux if the demand has changed
+ **/
+ @Override
+ public void pushDemand(FlowEdge supplierEdge, float newDemand) {
+ this.cpuEdge.pushDemand(newDemand);
+ }
+
+ /**
+ * Push supply to the workload if the supply has changed
+ **/
+ @Override
+ public void pushSupply(FlowEdge consumerEdge, float newSupply) {
+ this.workloadEdge.pushDemand(newSupply);
+ }
+
+ /**
+ * Handle new demand from the workload by sending it through to the cpuMux
+ **/
+ @Override
+ public void handleDemand(FlowEdge consumerEdge, float newDemand) {
+ if (this.cpuDemand == newDemand) {
+ return;
+ }
+
+ updateCounters(this.clock.millis());
+ this.cpuDemand = newDemand;
+
+ pushDemand(this.cpuEdge, newDemand);
+ }
+
+ /**
+ * Handle a new supply pushed by the cpuMux by sending it through to the workload
+ **/
+ @Override
+ public void handleSupply(FlowEdge supplierEdge, float newCpuSupply) {
+ if (newCpuSupply == this.cpuSupply) {
+ return;
+ }
+
+ updateCounters(this.clock.millis());
+ this.cpuSupply = newCpuSupply;
+
+ pushSupply(this.workloadEdge, newCpuSupply);
+ }
+
+ @Override
+ public void removeConsumerEdge(FlowEdge consumerEdge) {
+ this.workloadEdge = null;
+ this.shutdown();
+ }
+
+ @Override
+ public float getCapacity() {
+ return this.cpuCapacity;
+ }
+
+ @Override
+ public void removeSupplierEdge(FlowEdge supplierEdge) {
+ this.cpuEdge = null;
+ this.shutdown();
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PerformanceScalingGovernorTest.kt b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/memory/Memory.java
index f03f41fe..2656a99a 100644
--- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PerformanceScalingGovernorTest.kt
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/memory/Memory.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 AtLarge Research
+ * Copyright (c) 2024 AtLarge Research
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -20,31 +20,36 @@
* SOFTWARE.
*/
-package org.opendc.simulator.compute.kernel.cpufreq
+package org.opendc.simulator.compute.memory;
-import io.mockk.every
-import io.mockk.spyk
-import io.mockk.verify
-import org.junit.jupiter.api.Test
+import org.opendc.simulator.compute.models.MemoryUnit;
+import org.opendc.simulator.engine.FlowGraph;
/**
- * Test suite for the [PerformanceScalingGovernor]
+ * The [SimMemory] implementation for a machine.
*/
-internal class PerformanceScalingGovernorTest {
- @Test
- fun testSetStartLimit() {
- val policy = spyk<ScalingPolicy>()
- val logic = ScalingGovernors.performance().newGovernor(policy)
+public final class Memory {
+ // private final SimpleFlowSink sink;
+ private final MemoryUnit memoryUnit;
- every { policy.max } returns 4100.0
+ public Memory(FlowGraph graph, MemoryUnit memoryUnit) {
- logic.onStart()
- verify(exactly = 1) { policy.target = 4100.0 }
+ this.memoryUnit = memoryUnit;
+ // TODO: Fix this
+ // this.sink = new SimpleFlowSink(graph, (float) memoryUnit.getSize());
+ }
+
+ public double getCapacity() {
+ // return sink.getCapacity();
+ return 0.0f;
+ }
- logic.onLimit(0.0)
- verify(exactly = 1) { policy.target = 4100.0 }
+ public MemoryUnit getMemoryUnit() {
+ return memoryUnit;
+ }
- logic.onLimit(1.0)
- verify(exactly = 1) { policy.target = 4100.0 }
+ @Override
+ public String toString() {
+ return "SimAbstractMachine.Memory";
}
}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/NetworkAdapter.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/NetworkAdapter.java
deleted file mode 100644
index ff3daa40..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/NetworkAdapter.java
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (c) 2022 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.model;
-
-import java.util.Objects;
-
-/**
- * A description of a network adapter
- */
-public final class NetworkAdapter {
- private final String vendor;
- private final String modelName;
- private final double bandwidth;
-
- /**
- * Construct a {@link NetworkAdapter} instance.
- *
- * @param vendor The vendor of the storage device.
- * @param modelName The model name of the device.
- * @param bandwidth The bandwidth of the network adapter in Mbps.
- */
- public NetworkAdapter(String vendor, String modelName, double bandwidth) {
- this.vendor = vendor;
- this.modelName = modelName;
- this.bandwidth = bandwidth;
- }
-
- /**
- * Return the vendor of the storage device.
- */
- public String getVendor() {
- return vendor;
- }
-
- /**
- * Return the model name of the device.
- */
- public String getModelName() {
- return modelName;
- }
-
- /**
- * Return the bandwidth of the network adapter in Mbps.
- */
- public double getBandwidth() {
- return bandwidth;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- NetworkAdapter that = (NetworkAdapter) o;
- return Double.compare(that.bandwidth, bandwidth) == 0
- && vendor.equals(that.vendor)
- && modelName.equals(that.modelName);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(vendor, modelName, bandwidth);
- }
-
- @Override
- public String toString() {
- return "NetworkAdapter[vendor='" + vendor + "',modelName='" + modelName + "',bandwidth=" + bandwidth + "Mbps]";
- }
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/ProcessingNode.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/ProcessingNode.java
deleted file mode 100644
index 01a87b96..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/ProcessingNode.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright (c) 2022 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.model;
-
-import java.util.Objects;
-
-/**
- * A processing node/package/socket containing possibly several CPU cores.
- */
-public final class ProcessingNode {
- private final String vendor;
- private final String modelName;
- private final String arch;
- private final int coreCount;
-
- /**
- * Construct a {@link ProcessingNode} instance.
- *
- * @param vendor The vendor of the storage device.
- * @param modelName The model name of the device.
- * @param arch The micro-architecture of the processor node.
- * @param coreCount The number of logical CPUs in the processor node.
- */
- public ProcessingNode(String vendor, String modelName, String arch, int coreCount) {
- this.vendor = vendor;
- this.modelName = modelName;
- this.arch = arch;
- this.coreCount = coreCount;
- }
-
- /**
- * Return the vendor of the storage device.
- */
- public String getVendor() {
- return vendor;
- }
-
- /**
- * Return the model name of the device.
- */
- public String getModelName() {
- return modelName;
- }
-
- /**
- * Return the micro-architecture of the processor node.
- */
- public String getArchitecture() {
- return arch;
- }
-
- /**
- * Return the number of logical CPUs in the processor node.
- */
- public int getCoreCount() {
- return coreCount;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- ProcessingNode that = (ProcessingNode) o;
- return coreCount == that.coreCount
- && vendor.equals(that.vendor)
- && modelName.equals(that.modelName)
- && arch.equals(that.arch);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(vendor, modelName, arch, coreCount);
- }
-
- @Override
- public String toString() {
- return "ProcessingNode[vendor='" + vendor + "',modelName='" + modelName + "',arch=" + arch + ",coreCount="
- + coreCount + "]";
- }
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/StorageDevice.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/StorageDevice.java
deleted file mode 100644
index 549ccc7e..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/StorageDevice.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (c) 2022 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.model;
-
-import java.util.Objects;
-
-/**
- * Model for a physical storage device attached to a machine.
- */
-public final class StorageDevice {
- private final String vendor;
- private final String modelName;
- private final double capacity;
- private final double readBandwidth;
- private final double writeBandwidth;
-
- /**
- * Construct a {@link StorageDevice} instance.
- *
- * @param vendor The vendor of the storage device.
- * @param modelName The model name of the device.
- * @param capacity The capacity of the device.
- * @param readBandwidth The read bandwidth of the device in MBps.
- * @param writeBandwidth The write bandwidth of the device in MBps.
- */
- public StorageDevice(
- String vendor, String modelName, double capacity, double readBandwidth, double writeBandwidth) {
- this.vendor = vendor;
- this.modelName = modelName;
- this.capacity = capacity;
- this.readBandwidth = readBandwidth;
- this.writeBandwidth = writeBandwidth;
- }
-
- /**
- * Return the vendor of the storage device.
- */
- public String getVendor() {
- return vendor;
- }
-
- /**
- * Return the model name of the device.
- */
- public String getModelName() {
- return modelName;
- }
-
- /**
- * Return the capacity of the device.
- */
- public double getCapacity() {
- return capacity;
- }
-
- /**
- * Return the read bandwidth of the device in MBps.
- */
- public double getReadBandwidth() {
- return readBandwidth;
- }
-
- /**
- * Return the write bandwidth of the device in MBps.
- */
- public double getWriteBandwidth() {
- return writeBandwidth;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- StorageDevice that = (StorageDevice) o;
- return Double.compare(that.capacity, capacity) == 0
- && Double.compare(that.readBandwidth, readBandwidth) == 0
- && Double.compare(that.writeBandwidth, writeBandwidth) == 0
- && vendor.equals(that.vendor)
- && modelName.equals(that.modelName);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(vendor, modelName, capacity, readBandwidth, writeBandwidth);
- }
-
- @Override
- public String toString() {
- return "StorageDevice[vendor='" + vendor + "',modelName='" + modelName + "',capacity=" + capacity
- + ",readBandwidth=" + readBandwidth + ",writeBandwidth=" + writeBandwidth + "]";
- }
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/Cpu.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/models/CpuModel.java
index c319ae1a..88e17941 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/Cpu.java
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/models/CpuModel.java
@@ -20,25 +20,25 @@
* SOFTWARE.
*/
-package org.opendc.simulator.compute.model;
+package org.opendc.simulator.compute.models;
import java.util.Objects;
/**
* A single logical compute unit of processor node, either virtual or physical.
*/
-public final class Cpu {
+public final class CpuModel {
private final int id;
private final int coreCount;
- private final double coreSpeed;
- private final double totalCapacity;
+ private final float coreSpeed;
+ private final float totalCapacity;
private final String vendor;
private final String modelName;
private final String arch;
/**
- * Construct a {@link Cpu} instance.
+ * Construct a {@link CpuModel} instance.
*
* @param id The identifier of the CPU core within the processing node.
* @param coreCount The number of cores present in the CPU
@@ -47,7 +47,7 @@ public final class Cpu {
* @param modelName The name of the CPU
* @param arch The architecture of the CPU
*/
- public Cpu(int id, int coreCount, double coreSpeed, String vendor, String modelName, String arch) {
+ public CpuModel(int id, int coreCount, float coreSpeed, String vendor, String modelName, String arch) {
this.id = id;
this.coreCount = coreCount;
this.coreSpeed = coreSpeed;
@@ -57,7 +57,7 @@ public final class Cpu {
this.arch = arch;
}
- public Cpu(int id, int coreCount, double coreSpeed) {
+ public CpuModel(int id, int coreCount, float coreSpeed) {
this(id, coreCount, coreSpeed, "unkown", "unkown", "unkown");
}
@@ -78,14 +78,14 @@ public final class Cpu {
/**
* Return the clock rate of a single core of the CPU MHz.
*/
- public double getCoreSpeed() {
+ public float getCoreSpeed() {
return coreSpeed;
}
/**
* Return the clock rate of the CPU in MHz.
*/
- public double getTotalCapacity() {
+ public float getTotalCapacity() {
return totalCapacity;
}
@@ -114,7 +114,7 @@ public final class Cpu {
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
- Cpu that = (Cpu) o;
+ CpuModel that = (CpuModel) o;
return id == that.id
&& Double.compare(that.totalCapacity, totalCapacity) == 0
&& Double.compare(that.coreSpeed, coreSpeed) == 0
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/MachineModel.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/models/MachineModel.java
index e4019dac..d6d139d7 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/MachineModel.java
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/models/MachineModel.java
@@ -20,10 +20,8 @@
* SOFTWARE.
*/
-package org.opendc.simulator.compute.model;
+package org.opendc.simulator.compute.models;
-import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -31,33 +29,18 @@ import java.util.Objects;
* A description of the physical or virtual machine on which a bootable image runs.
*/
public final class MachineModel {
- private final Cpu cpu;
+ private final CpuModel cpuModel;
private final MemoryUnit memory;
- private final List<NetworkAdapter> net;
- private final List<StorageDevice> storage;
/**
* Construct a {@link MachineModel} instance.
*
- * @param cpu The cpu available to the image.
+ * @param cpuModel The cpu available to the image.
* @param memory The list of memory units available to the image.
- * @param net A list of network adapters available to the machine.
- * @param storage A list of storage devices available to the machine.
*/
- public MachineModel(Cpu cpu, MemoryUnit memory, Iterable<NetworkAdapter> net, Iterable<StorageDevice> storage) {
- this.cpu = cpu;
-
+ public MachineModel(CpuModel cpuModel, MemoryUnit memory) {
+ this.cpuModel = cpuModel;
this.memory = memory;
-
- this.net = new ArrayList<>();
- net.forEach(this.net::add);
-
- this.storage = new ArrayList<>();
- storage.forEach(this.storage::add);
- }
-
- public MachineModel(Cpu cpu, MemoryUnit memory) {
- this(cpu, memory, Collections.emptyList(), Collections.emptyList());
}
/**
@@ -68,31 +51,24 @@ public final class MachineModel {
* @param cpus The list of processing units available to the image.
* @param memory The list of memory units available to the image.
*/
- public MachineModel(
- List<Cpu> cpus, MemoryUnit memory, Iterable<NetworkAdapter> net, Iterable<StorageDevice> storage) {
+ public MachineModel(List<CpuModel> cpus, MemoryUnit memory) {
this(
- new Cpu(
+ new CpuModel(
cpus.get(0).getId(),
cpus.get(0).getCoreCount() * cpus.size(),
cpus.get(0).getCoreSpeed(),
cpus.get(0).getVendor(),
cpus.get(0).getModelName(),
cpus.get(0).getArchitecture()),
- memory,
- net,
- storage);
- }
-
- public MachineModel(List<Cpu> cpus, MemoryUnit memory) {
- this(cpus, memory, Collections.emptyList(), Collections.emptyList());
+ memory);
}
/**
* Return the processing units of this machine.
*/
- public Cpu getCpu() {
- return this.cpu;
+ public CpuModel getCpu() {
+ return this.cpuModel;
}
/**
@@ -102,38 +78,21 @@ public final class MachineModel {
return memory;
}
- /**
- * Return the network adapters of this machine.
- */
- public List<NetworkAdapter> getNetwork() {
- return Collections.unmodifiableList(net);
- }
-
- /**
- * Return the storage devices of this machine.
- */
- public List<StorageDevice> getStorage() {
- return Collections.unmodifiableList(storage);
- }
-
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MachineModel that = (MachineModel) o;
- return cpu.equals(that.cpu)
- && memory.equals(that.memory)
- && net.equals(that.net)
- && storage.equals(that.storage);
+ return cpuModel.equals(that.cpuModel) && memory.equals(that.memory);
}
@Override
public int hashCode() {
- return Objects.hash(cpu, memory, net, storage);
+ return Objects.hash(cpuModel, memory);
}
@Override
public String toString() {
- return "MachineModel[cpus=" + cpu + ",memory=" + memory + ",net=" + net + ",storage=" + storage + "]";
+ return "MachineModel[cpus=" + cpuModel + ",memory=" + memory + "]";
}
}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/MemoryUnit.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/models/MemoryUnit.java
index dbd3f89a..c3af2bcd 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/MemoryUnit.java
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/models/MemoryUnit.java
@@ -20,7 +20,7 @@
* SOFTWARE.
*/
-package org.opendc.simulator.compute.model;
+package org.opendc.simulator.compute.models;
import java.util.Objects;
@@ -34,7 +34,7 @@ public final class MemoryUnit {
private final long size;
/**
- * Construct a {@link ProcessingNode} instance.
+ * Construct a {@link MemoryUnit} instance.
*
* @param vendor The vendor of the storage device.
* @param modelName The model name of the device.
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/SimPowerSource.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/SimPowerSource.java
new file mode 100644
index 00000000..9b4d6a33
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/SimPowerSource.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2024 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package org.opendc.simulator.compute.power;
+
+import java.time.InstantSource;
+import org.opendc.simulator.compute.cpu.SimCpu;
+import org.opendc.simulator.engine.FlowEdge;
+import org.opendc.simulator.engine.FlowGraph;
+import org.opendc.simulator.engine.FlowNode;
+import org.opendc.simulator.engine.FlowSupplier;
+
+/**
+ * A {@link SimPsu} implementation that estimates the power consumption based on CPU usage.
+ */
+public final class SimPowerSource extends FlowNode implements FlowSupplier {
+ private final InstantSource clock;
+
+ private long lastUpdate;
+
+ private float powerDemand = 0.0f;
+ private float powerSupplied = 0.0f;
+ private float totalEnergyUsage = 0.0f;
+
+ private FlowEdge cpuEdge;
+
+ private float capacity = Long.MAX_VALUE;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Basic Getters and Setters
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Determine whether the InPort is connected to a {@link SimCpu}.
+ *
+ * @return <code>true</code> if the InPort is connected to an OutPort, <code>false</code> otherwise.
+ */
+ public boolean isConnected() {
+ return cpuEdge != null;
+ }
+
+ /**
+ * Return the power demand of the machine (in W) measured in the PSU.
+ * <p>
+ * This method provides access to the power consumption of the machine before PSU losses are applied.
+ */
+ public double getPowerDemand() {
+ return this.powerDemand;
+ }
+
+ /**
+ * Return the instantaneous power usage of the machine (in W) measured at the InPort of the power supply.
+ */
+ public float getPowerDraw() {
+ return this.powerSupplied;
+ }
+
+ /**
+ * Return the cumulated energy usage of the machine (in J) measured at the InPort of the powers supply.
+ */
+ public float getEnergyUsage() {
+ updateCounters();
+ return totalEnergyUsage;
+ }
+
+ @Override
+ public float getCapacity() {
+ return this.capacity;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Constructors
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ public SimPowerSource(FlowGraph graph) {
+ super(graph);
+
+ this.clock = graph.getEngine().getClock();
+
+ lastUpdate = graph.getEngine().getClock().millis();
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // FlowNode related functionality
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public long onUpdate(long now) {
+ updateCounters();
+ float powerSupply = this.powerDemand;
+
+ if (powerSupply != this.powerSupplied) {
+ this.pushSupply(this.cpuEdge, powerSupply);
+ }
+
+ return Long.MAX_VALUE;
+ }
+
+ public void updateCounters() {
+ updateCounters(clock.millis());
+ }
+
+ /**
+ * Calculate the energy usage up until <code>now</code>.
+ */
+ public void updateCounters(long now) {
+ long lastUpdate = this.lastUpdate;
+ this.lastUpdate = now;
+
+ long duration = now - lastUpdate;
+ if (duration > 0) {
+ // Compute the energy usage of the machine
+ this.totalEnergyUsage += (float) (this.powerSupplied * duration * 0.001);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // FlowGraph Related functionality
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public void handleDemand(FlowEdge consumerEdge, float newPowerDemand) {
+ if (newPowerDemand == this.powerDemand) {
+ return;
+ }
+
+ this.powerDemand = newPowerDemand;
+ this.invalidate();
+ }
+
+ @Override
+ public void pushSupply(FlowEdge consumerEdge, float newSupply) {
+ if (newSupply == this.powerSupplied) {
+ return;
+ }
+
+ this.powerSupplied = newSupply;
+ consumerEdge.pushSupply(newSupply);
+ }
+
+ @Override
+ public void addConsumerEdge(FlowEdge consumerEdge) {
+ this.cpuEdge = consumerEdge;
+ }
+
+ @Override
+ public void removeConsumerEdge(FlowEdge consumerEdge) {
+ this.cpuEdge = null;
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/SimPsu.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/SimPsu.java
new file mode 100644
index 00000000..8f0fb130
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/SimPsu.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2024 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package org.opendc.simulator.compute.power;
+
+import org.opendc.simulator.compute.cpu.SimCpu;
+import org.opendc.simulator.engine.FlowConsumer;
+import org.opendc.simulator.engine.FlowEdge;
+import org.opendc.simulator.engine.FlowGraph;
+import org.opendc.simulator.engine.FlowNode;
+import org.opendc.simulator.engine.FlowSupplier;
+
+/**
+ * A {@link SimPsu} implementation that estimates the power consumption based on CPU usage.
+ */
+public final class SimPsu extends FlowNode implements FlowSupplier, FlowConsumer {
+ private long lastUpdate;
+
+ private float powerDemand = 0.0f;
+ private float powerSupplied = 0.0f;
+ private float totalEnergyUsage = 0.0f;
+
+ private FlowEdge cpuEdge;
+ private FlowEdge powerEdge;
+
+ private float capacity = Long.MAX_VALUE;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Basic Getters and Setters
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Determine whether the InPort is connected to a {@link SimCpu}.
+ *
+ * @return <code>true</code> if the InPort is connected to an OutPort, <code>false</code> otherwise.
+ */
+ public boolean isConnected() {
+ return cpuEdge != null;
+ }
+
+ /**
+ * Return the power demand of the machine (in W) measured in the PSU.
+ * <p>
+ * This method provides access to the power consumption of the machine before PSU losses are applied.
+ */
+ public double getPowerDemand() {
+ return this.powerDemand;
+ }
+
+ /**
+ * Return the instantaneous power usage of the machine (in W) measured at the InPort of the power supply.
+ */
+ public float getPowerDraw() {
+ return this.powerSupplied;
+ }
+
+ /**
+ * Return the cumulated energy usage of the machine (in J) measured at the InPort of the powers supply.
+ */
+ public float getEnergyUsage() {
+ updateCounters();
+ return totalEnergyUsage;
+ }
+
+ @Override
+ public float getCapacity() {
+ return this.capacity;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Constructors
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ public SimPsu(FlowGraph graph) {
+ super(graph);
+
+ lastUpdate = this.clock.millis();
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // FlowNode related functionality
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public long onUpdate(long now) {
+ updateCounters();
+ float powerSupply = this.powerDemand;
+
+ if (powerSupply != this.powerSupplied) {
+ this.pushSupply(this.cpuEdge, powerSupply);
+ }
+
+ return Long.MAX_VALUE;
+ }
+
+ public void updateCounters() {
+ updateCounters(clock.millis());
+ }
+
+ /**
+ * Calculate the energy usage up until <code>now</code>.
+ */
+ public void updateCounters(long now) {
+ long lastUpdate = this.lastUpdate;
+ this.lastUpdate = now;
+
+ long duration = now - lastUpdate;
+ if (duration > 0) {
+ // Compute the energy usage of the psu
+ this.totalEnergyUsage += (float) (this.powerSupplied * duration * 0.001);
+ }
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // FlowGraph Related functionality
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public void pushDemand(FlowEdge supplierEdge, float newDemand) {
+ if (newDemand == this.powerDemand) {
+ return;
+ }
+
+ this.powerDemand = newDemand;
+ powerEdge.pushSupply(newDemand);
+ }
+
+ @Override
+ public void pushSupply(FlowEdge consumerEdge, float newSupply) {
+ if (newSupply == this.powerSupplied) {
+ return;
+ }
+
+ this.powerSupplied = newSupply;
+ cpuEdge.pushSupply(newSupply);
+ }
+
+ @Override
+ public void handleDemand(FlowEdge consumerEdge, float newPowerDemand) {
+ if (newPowerDemand == this.powerDemand) {
+ return;
+ }
+
+ this.powerDemand = newPowerDemand;
+ this.invalidate();
+ }
+
+ @Override
+ public void handleSupply(FlowEdge supplierEdge, float newPowerSupply) {
+ if (newPowerSupply == this.powerSupplied) {
+ return;
+ }
+
+ this.powerSupplied = newPowerSupply;
+ this.invalidate();
+ }
+
+ @Override
+ public void addConsumerEdge(FlowEdge consumerEdge) {
+ this.cpuEdge = consumerEdge;
+ }
+
+ @Override
+ public void addSupplierEdge(FlowEdge supplierEdge) {
+ this.powerEdge = supplierEdge;
+ }
+
+ @Override
+ public void removeConsumerEdge(FlowEdge consumerEdge) {
+ this.cpuEdge = null;
+ }
+
+ @Override
+ public void removeSupplierEdge(FlowEdge supplierEdge) {
+ this.powerEdge = null;
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/ChainWorkload.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/ChainWorkload.java
new file mode 100644
index 00000000..78e8b5d4
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/ChainWorkload.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2024 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package org.opendc.simulator.compute.workload;
+
+import java.util.ArrayList;
+import org.opendc.simulator.engine.FlowSupplier;
+
+public class ChainWorkload implements Workload {
+ private ArrayList<Workload> workloads;
+ private final long checkpointInterval;
+ private final long checkpointDuration;
+ private final double checkpointIntervalScaling;
+
+ public ChainWorkload(
+ ArrayList<Workload> workloads,
+ long checkpointInterval,
+ long checkpointDuration,
+ double checkpointIntervalScaling) {
+ this.workloads = workloads;
+ this.checkpointInterval = checkpointInterval;
+ this.checkpointDuration = checkpointDuration;
+ this.checkpointIntervalScaling = checkpointIntervalScaling;
+ }
+
+ public ArrayList<Workload> getWorkloads() {
+ return workloads;
+ }
+
+ public long getCheckpointInterval() {
+ return checkpointInterval;
+ }
+
+ public long getCheckpointDuration() {
+ return checkpointDuration;
+ }
+
+ public double getCheckpointIntervalScaling() {
+ return checkpointIntervalScaling;
+ }
+
+ public void removeWorkloads(int numberOfWorkloads) {
+ if (numberOfWorkloads <= 0) {
+ return;
+ }
+ this.workloads.subList(0, numberOfWorkloads).clear();
+ }
+
+ @Override
+ public SimWorkload startWorkload(FlowSupplier supplier, long now) {
+ return new SimChainWorkload(supplier, this, now);
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/CheckpointModel.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/CheckpointModel.java
new file mode 100644
index 00000000..723c450d
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/CheckpointModel.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2024 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package org.opendc.simulator.compute.workload;
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// CheckPoint Model
+// TODO: Move this to a separate file
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+import java.time.InstantSource;
+import org.jetbrains.annotations.NotNull;
+import org.opendc.simulator.engine.FlowGraph;
+import org.opendc.simulator.engine.FlowNode;
+
+public class CheckpointModel extends FlowNode {
+ private SimWorkload simWorkload;
+ private long checkpointInterval;
+ private final long checkpointDuration;
+ private double checkpointIntervalScaling;
+ private FlowGraph graph;
+
+ private long startOfInterval;
+
+ public CheckpointModel(@NotNull SimWorkload simWorkload) {
+ super(simWorkload.getGraph());
+
+ this.checkpointInterval = simWorkload.getCheckpointInterval();
+ this.checkpointDuration = simWorkload.getCheckpointDuration();
+ this.checkpointIntervalScaling = simWorkload.getCheckpointIntervalScaling();
+ this.simWorkload = simWorkload;
+
+ this.graph = simWorkload.getGraph();
+
+ InstantSource clock = graph.getEngine().getClock();
+
+ this.startOfInterval = clock.millis();
+ }
+
+ @Override
+ public long onUpdate(long now) {
+ if (this.simWorkload == null) {
+ return Long.MAX_VALUE;
+ }
+
+ long passedTime = now - startOfInterval;
+ long remainingTime = this.checkpointInterval - passedTime;
+
+ // Interval not completed
+ if (remainingTime > 0) {
+ return now + remainingTime;
+ }
+
+ simWorkload.makeSnapshot(now);
+
+ // start new fragment
+ this.startOfInterval = now - passedTime;
+
+ // Scale the interval time between checkpoints based on the provided scaling
+ this.checkpointInterval = (long) (this.checkpointInterval * this.checkpointIntervalScaling);
+
+ return now + this.checkpointInterval + this.checkpointDuration;
+ }
+
+ public void start() {
+ this.invalidate();
+ }
+
+ public void close() {
+ this.closeNode();
+
+ this.simWorkload = null;
+ this.graph = null;
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimChainWorkload.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimChainWorkload.java
index 1dcb3674..7f1cf060 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimChainWorkload.java
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimChainWorkload.java
@@ -22,59 +22,46 @@
package org.opendc.simulator.compute.workload;
-import java.time.InstantSource;
-import java.util.List;
-import java.util.Map;
-import org.opendc.simulator.compute.SimMachineContext;
-import org.opendc.simulator.compute.SimMemory;
-import org.opendc.simulator.compute.SimNetworkInterface;
-import org.opendc.simulator.compute.SimProcessingUnit;
-import org.opendc.simulator.compute.SimStorageInterface;
-import org.opendc.simulator.flow2.FlowGraph;
-import org.opendc.simulator.flow2.FlowStage;
-import org.opendc.simulator.flow2.FlowStageLogic;
+import java.util.LinkedList;
+import org.opendc.simulator.engine.FlowEdge;
+import org.opendc.simulator.engine.FlowNode;
+import org.opendc.simulator.engine.FlowSupplier;
/**
- * A {@link SimWorkload} that composes two {@link SimWorkload}s.
+ * A {@link SimChainWorkload} that composes multiple {@link SimWorkload}s.
*/
-final class SimChainWorkload implements SimWorkload {
- private final SimWorkload[] workloads;
- private int activeWorkloadIndex;
+final class SimChainWorkload extends SimWorkload implements FlowSupplier {
+ private final LinkedList<Workload> workloads;
+ private int workloadIndex;
- private SimChainWorkloadContext activeContext;
+ private SimWorkload activeWorkload;
+ private float demand = 0.0f;
+ private float supply = 0.0f;
+
+ private FlowEdge workloadEdge;
+ private FlowEdge machineEdge;
+
+ private float capacity = 0;
private long checkpointInterval = 0;
private long checkpointDuration = 0;
-
private double checkpointIntervalScaling = 1.0;
- private CheckPointModel checkpointModel;
- private SimChainWorkload snapshot;
+ private CheckpointModel checkpointModel;
- /**
- * Construct a {@link SimChainWorkload} instance.
- *
- * @param workloads The workloads to chain.
- * @param activeWorkloadIndex The index of the active workload.
- */
- SimChainWorkload(SimWorkload[] workloads, int activeWorkloadIndex) {
- this.workloads = workloads;
+ private ChainWorkload snapshot;
- if (this.workloads.length > 1) {
- checkpointInterval = this.workloads[1].getCheckpointInterval();
- checkpointDuration = this.workloads[1].getCheckpointDuration();
- checkpointIntervalScaling = this.workloads[1].getCheckpointIntervalScaling();
- }
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Basic Getters and Setters
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- this.activeWorkloadIndex = activeWorkloadIndex;
+ @Override
+ public float getCapacity() {
+ return this.capacity;
}
- /**
- * Construct a {@link SimChainWorkload} instance.
- *
- * @param workloads The workloads to chain.
- */
- SimChainWorkload(SimWorkload... workloads) {
- this(workloads, 0);
+ @Override
+ public ChainWorkload getSnapshot() {
+ return this.snapshot;
}
@Override
@@ -92,270 +79,202 @@ final class SimChainWorkload implements SimWorkload {
return checkpointIntervalScaling;
}
- @Override
- public void setOffset(long now) {
- for (SimWorkload workload : this.workloads) {
- workload.setOffset(now);
- }
- }
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Constructors
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- @Override
- public void onStart(SimMachineContext ctx) {
- final SimWorkload[] workloads = this.workloads;
- final int activeWorkloadIndex = this.activeWorkloadIndex;
+ SimChainWorkload(FlowSupplier supplier, ChainWorkload workload, long now) {
+ super(((FlowNode) supplier).getGraph());
- if (activeWorkloadIndex >= workloads.length) {
- return;
- }
+ this.snapshot = workload;
+
+ this.parentGraph = ((FlowNode) supplier).getGraph();
+ this.parentGraph.addEdge(this, supplier);
- final SimChainWorkloadContext context = new SimChainWorkloadContext(ctx);
- activeContext = context;
+ this.clock = this.parentGraph.getEngine().getClock();
+ this.workloads = new LinkedList<>(workload.getWorkloads());
+ this.checkpointInterval = workload.getCheckpointInterval();
+ this.checkpointDuration = workload.getCheckpointDuration();
+ this.checkpointIntervalScaling = workload.getCheckpointIntervalScaling();
if (checkpointInterval > 0) {
this.createCheckpointModel();
- this.checkpointModel.start();
}
- tryThrow(context.doStart(workloads[activeWorkloadIndex]));
+ this.workloadIndex = -1;
+
+ this.onStart();
}
- @Override
- public void onStop(SimMachineContext ctx) {
- final SimWorkload[] workloads = this.workloads;
- final int activeWorkloadIndex = this.activeWorkloadIndex;
+ public Workload getNextWorkload() {
+ this.workloadIndex++;
+ return workloads.pop();
+ }
- if (activeWorkloadIndex >= workloads.length) {
+ // TODO: Combine with Constructor
+ public void onStart() {
+ if (this.workloads.isEmpty()) {
return;
}
- final SimChainWorkloadContext context = activeContext;
- activeContext = null;
-
- if (this.checkpointModel != null) {
- this.checkpointModel.stop();
+ // Create and start a checkpoint model if initiated
+ if (checkpointInterval > 0) {
+ this.checkpointModel.start();
}
- tryThrow(context.doStop(workloads[activeWorkloadIndex]));
+ this.activeWorkload = this.getNextWorkload().startWorkload(this, this.clock.millis());
}
@Override
- public void makeSnapshot(long now) {
- final int activeWorkloadIndex = this.activeWorkloadIndex;
- final SimWorkload[] workloads = this.workloads;
- final SimWorkload[] newWorkloads = new SimWorkload[workloads.length - activeWorkloadIndex];
+ public long onUpdate(long now) {
+ return Long.MAX_VALUE;
+ }
- for (int i = 0; i < newWorkloads.length; i++) {
- workloads[activeWorkloadIndex + i].makeSnapshot(now);
- newWorkloads[i] = workloads[activeWorkloadIndex + i].getSnapshot();
+ @Override
+ public void stopWorkload() {
+ if (this.checkpointModel != null) {
+ this.checkpointModel.close();
+ this.checkpointModel = null;
}
- this.snapshot = new SimChainWorkload(newWorkloads, 0);
- }
+ if (this.activeWorkload != null) {
+ this.activeWorkload.stopWorkload();
+ this.activeWorkload = null;
+ }
- @Override
- public SimChainWorkload getSnapshot() {
- return this.snapshot;
+ this.closeNode();
}
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Checkpoint related functionality
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
@Override
public void createCheckpointModel() {
- this.checkpointModel = new CheckPointModel(
- activeContext, this, this.checkpointInterval, this.checkpointDuration, this.checkpointIntervalScaling);
+ this.checkpointModel = new CheckpointModel(this);
}
- private class CheckPointModel implements FlowStageLogic {
- private SimChainWorkload workload;
- private long checkpointInterval;
- private long checkpointDuration;
- private double checkpointIntervalScaling;
- private FlowStage stage;
-
- private long startOfInterval;
- private Boolean firstCheckPoint = true;
-
- CheckPointModel(
- SimChainWorkloadContext context,
- SimChainWorkload workload,
- long checkpointInterval,
- long checkpointDuration,
- double checkpointIntervalScaling) {
- this.checkpointInterval = checkpointInterval;
- this.checkpointDuration = checkpointDuration;
- this.checkpointIntervalScaling = checkpointIntervalScaling;
- this.workload = workload;
-
- this.stage = context.getGraph().newStage(this);
-
- InstantSource clock = this.stage.getGraph().getEngine().getClock();
-
- this.startOfInterval = clock.millis();
- }
-
- @Override
- public long onUpdate(FlowStage ctx, long now) {
- long passedTime = now - startOfInterval;
- long remainingTime = this.checkpointInterval - passedTime;
-
- if (!this.firstCheckPoint) {
- remainingTime += this.checkpointDuration;
- }
-
- // Interval not completed
- if (remainingTime > 0) {
- return now + remainingTime;
- }
-
- workload.makeSnapshot(now);
- if (firstCheckPoint) {
- this.firstCheckPoint = false;
- }
+ @Override
+ public void makeSnapshot(long now) {
- // Scale the interval time between checkpoints based on the provided scaling
- this.checkpointInterval = (long) (this.checkpointInterval * this.checkpointIntervalScaling);
+ this.snapshot.removeWorkloads(this.workloadIndex);
+ this.workloadIndex = 0;
- return now + this.checkpointInterval + this.checkpointDuration;
- }
+ activeWorkload.makeSnapshot(now);
+ }
- public void start() {
- this.stage.sync();
- }
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // FlowGraph Related functionality
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- public void stop() {
- this.stage.close();
- }
+ /**
+ * Add connection to the active workload
+ *
+ * @param consumerEdge
+ */
+ @Override
+ public void addConsumerEdge(FlowEdge consumerEdge) {
+ this.workloadEdge = consumerEdge;
}
/**
- * A {@link SimMachineContext} that intercepts the shutdown calls.
+ * Add Connection to the cpuMux
+ * @param supplierEdge
*/
- private class SimChainWorkloadContext implements SimMachineContext {
- private final SimMachineContext ctx;
- private SimWorkload snapshot;
-
- private SimChainWorkloadContext(SimMachineContext ctx) {
- this.ctx = ctx;
- }
-
- @Override
- public FlowGraph getGraph() {
- return ctx.getGraph();
- }
-
- @Override
- public Map<String, Object> getMeta() {
- return ctx.getMeta();
- }
+ @Override
+ public void addSupplierEdge(FlowEdge supplierEdge) {
+ this.machineEdge = supplierEdge;
+ this.capacity = supplierEdge.getCapacity();
+ }
- @Override
- public SimProcessingUnit getCpu() {
- return ctx.getCpu();
- }
+ /**
+ * Push demand to the cpuMux
+ *
+ * @param supplierEdge
+ * @param newDemand
+ */
+ @Override
+ public void pushDemand(FlowEdge supplierEdge, float newDemand) {
+ this.machineEdge.pushDemand(newDemand);
+ }
- @Override
- public SimMemory getMemory() {
- return ctx.getMemory();
- }
+ /**
+ * Push supply to the workload
+ *
+ * @param consumerEdge
+ * @param newSupply
+ */
+ @Override
+ public void pushSupply(FlowEdge consumerEdge, float newSupply) {
+ this.workloadEdge.pushSupply(newSupply);
+ }
- @Override
- public List<? extends SimNetworkInterface> getNetworkInterfaces() {
- return ctx.getNetworkInterfaces();
+ /**
+ * Handle new demand coming from the workload
+ *
+ * @param consumerEdge
+ * @param newDemand
+ */
+ @Override
+ public void handleDemand(FlowEdge consumerEdge, float newDemand) {
+ if (newDemand == this.demand) {
+ return;
}
- @Override
- public List<? extends SimStorageInterface> getStorageInterfaces() {
- return ctx.getStorageInterfaces();
- }
+ this.demand = newDemand;
+ this.pushDemand(this.machineEdge, newDemand);
+ }
- @Override
- public void makeSnapshot(long now) {
- final SimWorkload workload = workloads[activeWorkloadIndex];
- this.snapshot = workload.getSnapshot();
+ /**
+ * Handle new supply coming from the cpuMux
+ *
+ * @param supplierEdge
+ * @param newSupply
+ */
+ @Override
+ public void handleSupply(FlowEdge supplierEdge, float newSupply) {
+ if (newSupply == this.supply) {
+ return;
}
- @Override
- public SimWorkload getSnapshot(long now) {
- this.makeSnapshot(now);
-
- return this.snapshot;
- }
+ this.pushSupply(this.machineEdge, newSupply);
+ }
- @Override
- public void reset() {
- ctx.reset();
+ /**
+ * Handle the removal of the workload.
+ * If there is a next workload available, start this workload
+ * Otherwise, close this SimChainWorkload
+ *
+ * @param consumerEdge
+ */
+ @Override
+ public void removeConsumerEdge(FlowEdge consumerEdge) {
+ if (this.workloadEdge == null) {
+ return;
}
- @Override
- public void shutdown() {
- shutdown(null);
- }
+ // Remove the connection to the active workload
+ this.activeWorkload = null;
+ this.workloadEdge = null;
- @Override
- public void shutdown(Exception cause) {
- final SimWorkload[] workloads = SimChainWorkload.this.workloads;
- final int activeWorkloadIndex = ++SimChainWorkload.this.activeWorkloadIndex;
-
- final Exception stopException = doStop(workloads[activeWorkloadIndex - 1]);
- if (cause == null) {
- cause = stopException;
- } else if (stopException != null) {
- cause.addSuppressed(stopException);
- }
-
- if (stopException == null && activeWorkloadIndex < workloads.length) {
- ctx.reset();
-
- final Exception startException = doStart(workloads[activeWorkloadIndex]);
-
- if (startException == null) {
- return;
- } else if (cause == null) {
- cause = startException;
- } else {
- cause.addSuppressed(startException);
- }
- }
-
- if (SimChainWorkload.this.checkpointModel != null) {
- SimChainWorkload.this.checkpointModel.stop();
- }
- ctx.shutdown(cause);
+ // Start next workload
+ if (!this.workloads.isEmpty()) {
+ this.activeWorkload = getNextWorkload().startWorkload(this, this.clock.millis());
+ return;
}
- /**
- * Start the specified workload.
- *
- * @return The {@link Exception} that occurred while starting the workload or <code>null</code> if the workload
- * started successfully.
- */
- private Exception doStart(SimWorkload workload) {
- try {
- workload.onStart(this);
- } catch (Exception cause) {
- final Exception stopException = doStop(workload);
- if (stopException != null) {
- cause.addSuppressed(stopException);
- }
- return cause;
- }
-
- return null;
- }
+ this.stopWorkload();
+ }
- /**
- * Stop the specified workload.
- *
- * @return The {@link Exception} that occurred while stopping the workload or <code>null</code> if the workload
- * stopped successfully.
- */
- private Exception doStop(SimWorkload workload) {
- try {
- workload.onStop(this);
- } catch (Exception cause) {
- return cause;
- }
-
- return null;
- }
+ /**
+ * Handle the removal of the connection to the cpuMux
+ * When this happens, close the SimChainWorkload
+ *
+ * @param supplierEdge
+ */
+ @Override
+ public void removeSupplierEdge(FlowEdge supplierEdge) {
+ this.stopWorkload();
}
@SuppressWarnings("unchecked")
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimFlopsWorkload.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimFlopsWorkload.java
deleted file mode 100644
index 5311fa38..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimFlopsWorkload.java
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright (c) 2022 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.SimMachineContext;
-import org.opendc.simulator.compute.SimProcessingUnit;
-import org.opendc.simulator.flow2.FlowGraph;
-import org.opendc.simulator.flow2.FlowStage;
-import org.opendc.simulator.flow2.FlowStageLogic;
-import org.opendc.simulator.flow2.OutPort;
-
-/**
- * A {@link SimWorkload} that models applications as a static number of floating point operations executed on
- * multiple cores of a compute resource.
- */
-public class SimFlopsWorkload implements SimWorkload, FlowStageLogic {
- private final long flops;
- private final double utilization;
-
- private SimMachineContext ctx;
- private FlowStage stage;
- private OutPort[] outputs;
-
- private float remainingAmount;
- private long lastUpdate;
- private SimFlopsWorkload snapshot;
-
- /**
- * Construct a new {@link SimFlopsWorkload}.
- *
- * @param flops The number of floating point operations to perform for this task in MFLOPs.
- * @param utilization The CPU utilization of the workload.
- */
- SimFlopsWorkload(long flops, double utilization) {
- if (flops < 0) {
- throw new IllegalArgumentException("Number of FLOPs must be positive");
- } else if (utilization <= 0.0 || utilization > 1.0) {
- throw new IllegalArgumentException("Utilization must be in (0, 1]");
- }
-
- this.flops = flops;
- this.utilization = utilization;
- this.remainingAmount = flops;
- }
-
- @Override
- public long getCheckpointInterval() {
- return -1;
- }
- ;
-
- @Override
- public long getCheckpointDuration() {
- return -1;
- }
-
- @Override
- public double getCheckpointIntervalScaling() {
- return -1;
- }
- ;
-
- @Override
- public void setOffset(long now) {}
-
- @Override
- public void onStart(SimMachineContext ctx) {
- this.ctx = ctx;
-
- final FlowGraph graph = ctx.getGraph();
- final FlowStage stage = graph.newStage(this);
- this.stage = stage;
-
- final SimProcessingUnit cpu = ctx.getCpu();
- final OutPort[] outputs = new OutPort[1];
- this.outputs = outputs;
-
- final OutPort output = stage.getOutlet("cpu");
-
- graph.connect(output, cpu.getInput());
- outputs[0] = output;
-
- this.remainingAmount = flops;
- this.lastUpdate = graph.getEngine().getClock().millis();
- }
-
- @Override
- public void onStop(SimMachineContext ctx) {
- this.ctx = null;
-
- final FlowStage stage = this.stage;
- if (stage != null) {
- this.stage = null;
- stage.close();
- }
- }
-
- @Override
- public void makeSnapshot(long now) {
- final FlowStage stage = this.stage;
- if (stage != null) {
- stage.sync();
- }
-
- this.snapshot = new SimFlopsWorkload((long) remainingAmount, utilization);
- }
-
- @Override
- public SimFlopsWorkload getSnapshot() {
- this.makeSnapshot(0);
-
- return this.snapshot;
- }
-
- @Override
- public void createCheckpointModel() {}
-
- @Override
- public long onUpdate(FlowStage ctx, long now) {
- long lastUpdate = this.lastUpdate;
- this.lastUpdate = now;
-
- long delta = Math.max(0, now - lastUpdate);
-
- float consumed = 0.f;
- float limit = 0.f;
-
- for (final OutPort output : outputs) {
- consumed += output.getRate() * delta;
-
- float outputLimit = (float) (output.getCapacity() * utilization);
- limit += outputLimit;
-
- output.push(outputLimit);
- }
- consumed = (float) (consumed * 0.001);
-
- float remainingAmount = this.remainingAmount - consumed;
- this.remainingAmount = remainingAmount;
-
- long duration = (long) Math.ceil(remainingAmount / limit * 1000);
-
- if (duration <= 0) {
- final SimMachineContext machineContext = this.ctx;
- if (machineContext != null) {
- machineContext.shutdown();
- }
- ctx.close();
- return Long.MAX_VALUE;
- }
-
- return now + duration;
- }
-
- @Override
- public String toString() {
- return "SimFlopsWorkload[FLOPs=" + flops + ",utilization=" + utilization + "]";
- }
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimRuntimeWorkload.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimRuntimeWorkload.java
deleted file mode 100644
index be4cc2f5..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimRuntimeWorkload.java
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Copyright (c) 2022 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.SimMachineContext;
-import org.opendc.simulator.compute.SimProcessingUnit;
-import org.opendc.simulator.flow2.FlowGraph;
-import org.opendc.simulator.flow2.FlowStage;
-import org.opendc.simulator.flow2.FlowStageLogic;
-import org.opendc.simulator.flow2.OutPort;
-
-/**
- * A [SimWorkload] that models application execution as a single duration.
- */
-public class SimRuntimeWorkload implements SimWorkload, FlowStageLogic {
- private long duration;
- private final double utilization;
-
- private SimMachineContext ctx;
- private FlowStage stage;
- private OutPort[] outputs;
-
- private long remainingDuration;
- private long lastUpdate;
-
- private long checkpointDuration; // How long does it take to make a checkpoint?
- private long checkpointInterval; // How long to wait until a new checkpoint is made?
- private double checkpointIntervalScaling;
- private long totalChecks;
- private SimRuntimeWorkload snapshot;
-
- public SimRuntimeWorkload(long duration, double utilization) {
- this(duration, utilization, 0, 0);
- // if (duration < 0) {
- // throw new IllegalArgumentException("Duration must be positive");
- // } else if (utilization <= 0.0 || utilization > 1.0) {
- // throw new IllegalArgumentException("Utilization must be in (0, 1]");
- // }
- //
- // this.checkpointTime = 0L;
- // this.checkpointWait = 0L;
- // this.duration = duration;
- //
- // this.utilization = utilization;
- // this.remainingDuration = duration;
- }
-
- /**
- * Construct a new {@link SimRuntimeWorkload}.
- *
- * @param duration The duration of the workload in milliseconds.
- * @param utilization The CPU utilization of the workload.
- */
- public SimRuntimeWorkload(long duration, double utilization, long checkpointInterval, long checkpointDuration) {
- if (duration < 0) {
- throw new IllegalArgumentException("Duration must be positive");
- } else if (utilization <= 0.0 || utilization > 1.0) {
- throw new IllegalArgumentException("Utilization must be in (0, 1]");
- }
-
- this.checkpointDuration = checkpointDuration;
- this.checkpointInterval = checkpointInterval;
- this.duration = duration;
-
- if (this.checkpointInterval > 0) {
- // Determine the number of checkpoints that need to be made during the workload
- // If the total duration is divisible by the wait time between checkpoints, we can remove the last
- // checkpoint
- int to_remove = ((this.duration % this.checkpointInterval == 0) ? 1 : 0);
- this.totalChecks = this.duration / this.checkpointInterval - to_remove;
- this.duration += (this.checkpointDuration * totalChecks);
- }
-
- this.utilization = utilization;
- this.remainingDuration = duration;
- }
-
- @Override
- public long getCheckpointInterval() {
- return checkpointInterval;
- }
-
- @Override
- public long getCheckpointDuration() {
- return checkpointDuration;
- }
-
- @Override
- public double getCheckpointIntervalScaling() {
- return checkpointIntervalScaling;
- }
-
- @Override
- public void setOffset(long now) {}
-
- @Override
- public void onStart(SimMachineContext ctx) {
- this.ctx = ctx;
-
- final FlowGraph graph = ctx.getGraph();
- final FlowStage stage = graph.newStage(this);
- this.stage = stage;
-
- final OutPort[] outputs = new OutPort[1];
- this.outputs = outputs;
-
- final SimProcessingUnit cpu = ctx.getCpu();
- final OutPort output = stage.getOutlet("cpu");
-
- graph.connect(output, cpu.getInput());
- outputs[0] = output;
-
- this.remainingDuration = duration;
- this.lastUpdate = graph.getEngine().getClock().millis();
- }
-
- @Override
- public void onStop(SimMachineContext ctx) {
- this.ctx = null;
-
- final FlowStage stage = this.stage;
- if (stage != null) {
- this.stage = null;
- this.outputs = null;
- stage.close();
- }
- }
-
- @Override
- public void makeSnapshot(long now) {
- System.out.printf("SimRuntimeWorkload -> makeSnapshot(%d)%n", now);
-
- final FlowStage stage = this.stage;
- if (stage != null) {
- stage.sync();
- }
-
- var remaining_time = this.remainingDuration;
-
- if (this.checkpointInterval > 0) {
- // Calculate last checkpoint
- var total_check_time = this.checkpointInterval + this.checkpointDuration;
- var processed_time = this.duration - this.remainingDuration;
- var processed_checks = (int) (processed_time / total_check_time);
- var processed_time_last_check =
- (processed_checks * total_check_time); // The processed time after the last checkpoint
-
- remaining_time = this.duration
- - processed_time_last_check; // The remaining duration to process after last checkpoint
- var remaining_checks = (int) (remaining_time / total_check_time);
- remaining_time -= (remaining_checks * checkpointDuration);
- } else {
- remaining_time = duration;
- }
-
- this.snapshot =
- new SimRuntimeWorkload(remaining_time, utilization, this.checkpointInterval, this.checkpointDuration);
- }
-
- @Override
- public SimRuntimeWorkload getSnapshot() {
- System.out.println("SimRuntimeWorkload -> getSnapshot()");
-
- return this.snapshot;
- }
-
- @Override
- public void createCheckpointModel() {}
-
- @Override
- public long onUpdate(FlowStage ctx, long now) {
- long lastUpdate = this.lastUpdate;
- this.lastUpdate = now;
-
- long delta = now - lastUpdate;
- long duration = this.remainingDuration - delta;
-
- if (delta == 0 && this.ctx == null) {
- // This means the workload has been terminated
- // But, has not executed to completion
- return Long.MAX_VALUE;
- }
-
- if (duration <= 0) {
- final SimMachineContext machineContext = this.ctx;
- if (machineContext != null) {
- machineContext.shutdown();
- }
- ctx.close();
- return Long.MAX_VALUE;
- }
-
- this.remainingDuration = duration;
-
- for (final OutPort output : outputs) {
- float limit = (float) (output.getCapacity() * utilization);
- output.push(limit);
- }
-
- return now + duration;
- }
-
- @Override
- public String toString() {
- return "SimDurationWorkload[duration=" + duration + "ms,utilization=" + utilization + "]";
- }
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimTrace.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimTrace.java
deleted file mode 100644
index b8445a9c..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimTrace.java
+++ /dev/null
@@ -1,413 +0,0 @@
-/*
- * Copyright (c) 2022 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 java.util.ArrayDeque;
-import java.util.Iterator;
-import java.util.List;
-import org.opendc.simulator.compute.SimMachineContext;
-import org.opendc.simulator.compute.SimProcessingUnit;
-import org.opendc.simulator.flow2.FlowGraph;
-import org.opendc.simulator.flow2.FlowStage;
-import org.opendc.simulator.flow2.FlowStageLogic;
-import org.opendc.simulator.flow2.OutPort;
-
-/**
- * A workload trace that describes the resource utilization over time in a collection of {@link SimTraceFragment}s.
- */
-public final class SimTrace {
- private final ArrayDeque<SimTraceFragment> fragments;
- /**
- * Construct a {@link SimTrace} instance.
- *
- */
- private SimTrace(ArrayDeque<SimTraceFragment> fragments) {
- if (fragments.isEmpty()) {
- throw new IllegalArgumentException("No Fragments found for the Trace");
- }
- this.fragments = fragments;
- }
-
- /**
- * Construct a {@link SimWorkload} for this trace.
- *
- * // * @param offset The offset for the timestamps.
- */
- public SimWorkload createWorkload(long start) {
- return createWorkload(start, 0, 0, 1);
- }
-
- /**
- * Construct a {@link SimWorkload} for this trace.
- *
- * // * @param offset The offset for the timestamps.
- */
- public SimWorkload createWorkload(
- long start, long checkpointInterval, long checkpointDuration, double checkpointIntervalScaling) {
- return new Workload(start, fragments, checkpointInterval, checkpointDuration, checkpointIntervalScaling);
- }
-
- // /**
- // * Create a new {@link Builder} instance with a default initial capacity.
- // */
- public static Builder builder() {
- return new Builder();
- }
-
- /**
- * Construct a {@link SimTrace} from the specified fragments.
- *
- * @param fragments The array of fragments to construct the trace from.
- */
- public static SimTrace ofFragments(SimTraceFragment... fragments) {
- final Builder builder = builder();
-
- for (SimTraceFragment fragment : fragments) {
- builder.add(fragment.duration(), fragment.cpuUsage(), fragment.coreCount());
- }
-
- return builder.build();
- }
-
- /**
- * Construct a {@link SimTrace} from the specified fragments.
- *
- * @param fragments The fragments to construct the trace from.
- */
- public static SimTrace ofFragments(List<SimTraceFragment> fragments) {
- final Builder builder = builder();
-
- for (SimTraceFragment fragment : fragments) {
- builder.add(fragment.duration(), fragment.cpuUsage(), fragment.coreCount());
- }
-
- return builder.build();
- }
-
- /**
- * Builder class for a {@link SimTrace}.
- */
- public static final class Builder {
- private final ArrayDeque<SimTraceFragment> fragments;
-
- private boolean isBuilt;
-
- /**
- * Construct a new {@link Builder} instance.
- */
- private Builder() {
- this.fragments = new ArrayDeque<>();
- }
-
- /**
- * Add a fragment to the trace.
- *
- * @param duration The timestamp at which the fragment ends (in epoch millis).
- * @param usage The CPU usage at this fragment.
- * @param cores The number of cores used during this fragment.
- */
- public void add(long duration, double usage, int cores) {
- if (isBuilt) {
- recreate();
- }
-
- fragments.add(new SimTraceFragment(duration, usage, cores));
- }
-
- /**
- * Build the {@link SimTrace} instance.
- */
- public SimTrace build() {
- isBuilt = true;
- return new SimTrace(fragments);
- }
-
- /**
- * Clone the columns of the trace.
- *
- * <p>
- * This is necessary when a {@link SimTrace} has been built already, but the user is again adding entries to
- * the builder.
- */
- private void recreate() {
- isBuilt = false;
- this.fragments.clear();
- }
- }
-
- /**
- * Implementation of {@link SimWorkload} that executes a trace.
- */
- private static class Workload implements SimWorkload {
- private WorkloadStageLogic logic;
-
- private long offset;
-
- private final long start;
- private ArrayDeque<SimTraceFragment> fragments;
-
- private long checkpointInterval; // How long to wait until a new checkpoint is made
- private long checkpointDuration; // How long does it take to make a checkpoint
- private double checkpointIntervalScaling;
- private SimWorkload snapshot;
-
- private Workload(
- long start,
- ArrayDeque<SimTraceFragment> fragments,
- long checkpointInterval,
- long checkpointDuration,
- double checkpointIntervalScaling) {
- this.start = start;
- this.checkpointInterval = checkpointInterval;
- this.checkpointDuration = checkpointDuration;
- this.checkpointIntervalScaling = checkpointIntervalScaling;
-
- this.fragments = fragments;
-
- this.snapshot = this;
- }
-
- @Override
- public long getCheckpointInterval() {
- return checkpointInterval;
- }
-
- @Override
- public long getCheckpointDuration() {
- return checkpointDuration;
- }
-
- @Override
- public double getCheckpointIntervalScaling() {
- return checkpointIntervalScaling;
- }
-
- @Override
- public void setOffset(long now) {
- this.offset = now;
- }
-
- @Override
- public void onStart(SimMachineContext ctx) {
- final WorkloadStageLogic logic;
- logic = new SingleWorkloadLogic(ctx, offset, fragments.iterator());
- this.logic = logic;
- }
-
- @Override
- public void onStop(SimMachineContext ctx) {
- final WorkloadStageLogic logic = this.logic;
-
- if (logic != null) {
- this.logic = null;
- logic.getStage().close();
- }
- }
-
- @Override
- public void makeSnapshot(long now) {
- final WorkloadStageLogic logic = this.logic;
- final ArrayDeque<SimTraceFragment> newFragments = this.fragments;
-
- if (logic != null) {
- int index = logic.getIndex();
-
- if (index == 0 && (logic.getPassedTime(now) == 0)) {
- this.snapshot = this;
- return;
- }
-
- // Remove all finished fragments
- for (int i = 0; i < index; i++) {
- newFragments.removeFirst();
- }
- } else {
- return;
- }
-
- // Reduce the current Fragment to a fragment with the remaining time.
- SimTraceFragment currentFragment = newFragments.pop();
- long passedTime = logic.getPassedTime(now);
- long remainingTime = currentFragment.duration() - passedTime;
-
- if (remainingTime > 0) {
- SimTraceFragment newFragment =
- new SimTraceFragment(remainingTime, currentFragment.cpuUsage(), currentFragment.coreCount());
-
- newFragments.addFirst(newFragment);
- }
-
- // Add snapshot Fragment
- // TODO: improve CPUUsage and coreCount here
- SimTraceFragment snapshotFragment = new SimTraceFragment(checkpointDuration, 123456, 1);
- newFragments.addFirst(snapshotFragment);
-
- // Update the logic
- this.logic.updateFragments(newFragments.iterator(), now);
-
- // remove the snapshot Fragment and update fragments
- newFragments.removeFirst();
- this.fragments = newFragments;
-
- this.snapshot = new Workload(
- start, this.fragments, checkpointInterval, checkpointDuration, checkpointIntervalScaling);
- }
-
- @Override
- public SimWorkload getSnapshot() {
- return this.snapshot;
- }
-
- @Override
- public void createCheckpointModel() {}
- }
-
- /**
- * Interface to represent the {@link FlowStage} that simulates the trace workload.
- */
- private interface WorkloadStageLogic extends FlowStageLogic {
- /**
- * Return the {@link FlowStage} belonging to this instance.
- */
- FlowStage getStage();
-
- long getPassedTime(long now);
-
- void updateFragments(Iterator<SimTraceFragment> newFragments, long offset);
-
- /**
- * Return the current index of the workload.
- */
- int getIndex();
- }
-
- /**
- * Implementation of {@link FlowStageLogic} for just a single CPU resource.
- */
- private static class SingleWorkloadLogic implements WorkloadStageLogic {
- private final FlowStage stage;
- private final OutPort output;
- private int index = 0;
-
- private final SimMachineContext ctx;
-
- private Iterator<SimTraceFragment> fragments;
- private SimTraceFragment currentFragment;
- private long startOffFragment;
-
- private SingleWorkloadLogic(SimMachineContext ctx, long offset, Iterator<SimTraceFragment> fragments) {
- this.ctx = ctx;
-
- this.fragments = fragments;
-
- final FlowGraph graph = ctx.getGraph();
- stage = graph.newStage(this);
-
- final SimProcessingUnit cpu = ctx.getCpu();
- final OutPort output = stage.getOutlet("cpu");
- this.output = output;
-
- graph.connect(output, cpu.getInput());
-
- // Start the first Fragment
- this.currentFragment = this.fragments.next();
- this.output.push((float) currentFragment.cpuUsage());
- this.startOffFragment = offset;
- }
-
- public long getPassedTime(long now) {
- return now - this.startOffFragment;
- }
-
- @Override
- public void updateFragments(Iterator<SimTraceFragment> newFragments, long offset) {
- this.fragments = newFragments;
-
- // Start the first Fragment
- this.currentFragment = this.fragments.next();
- this.output.push((float) currentFragment.cpuUsage());
- this.startOffFragment = offset;
-
- this.index = -1;
-
- this.stage.invalidate();
- }
-
- @Override
- public long onUpdate(FlowStage ctx, long now) {
- long passedTime = getPassedTime(now);
- long duration = this.currentFragment.duration();
-
- // The current Fragment has not yet been finished, continue
- if (passedTime < duration) {
- return now + (duration - passedTime);
- }
-
- // Loop through fragments until the passed time is filled.
- // We need a while loop to account for skipping of fragments.
- while (passedTime >= duration) {
- if (!this.fragments.hasNext()) {
- return doStop(ctx);
- }
-
- passedTime = passedTime - duration;
-
- // get next Fragment
- this.index++;
- currentFragment = this.fragments.next();
- duration = currentFragment.duration();
- }
-
- // start new fragment
- this.startOffFragment = now - passedTime;
-
- // Change the cpu Usage to the new Fragment
- this.output.push((float) currentFragment.cpuUsage());
-
- // Return the time when the current fragment will complete
- return this.startOffFragment + duration;
- }
-
- @Override
- public FlowStage getStage() {
- return stage;
- }
-
- @Override
- public int getIndex() {
- return index;
- }
-
- /**
- * Helper method to stop the execution of the workload.
- */
- private long doStop(FlowStage ctx) {
- final SimMachineContext machineContext = this.ctx;
- if (machineContext != null) {
- machineContext.shutdown();
- }
- ctx.close();
- return Long.MAX_VALUE;
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimTraceWorkload.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimTraceWorkload.java
new file mode 100644
index 00000000..b6f98344
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimTraceWorkload.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright (c) 2024 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package org.opendc.simulator.compute.workload;
+
+import java.util.LinkedList;
+import org.opendc.simulator.engine.FlowConsumer;
+import org.opendc.simulator.engine.FlowEdge;
+import org.opendc.simulator.engine.FlowGraph;
+import org.opendc.simulator.engine.FlowNode;
+import org.opendc.simulator.engine.FlowSupplier;
+
+public class SimTraceWorkload extends SimWorkload implements FlowConsumer {
+ private LinkedList<TraceFragment> remainingFragments;
+ private int fragmentIndex;
+
+ private TraceFragment currentFragment;
+ private long startOfFragment;
+
+ private FlowEdge machineEdge;
+ private float currentDemand;
+ private float currentSupply;
+
+ private long checkpointInterval;
+ private long checkpointDuration;
+ private double checkpointIntervalScaling;
+
+ private TraceWorkload snapshot;
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Basic Getters and Setters
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ public long getPassedTime(long now) {
+ return now - this.startOfFragment;
+ }
+
+ public TraceWorkload getSnapshot() {
+ return snapshot;
+ }
+
+ @Override
+ long getCheckpointInterval() {
+ return 0;
+ }
+
+ @Override
+ long getCheckpointDuration() {
+ return 0;
+ }
+
+ @Override
+ double getCheckpointIntervalScaling() {
+ return 0;
+ }
+
+ public TraceFragment getNextFragment() {
+ this.currentFragment = this.remainingFragments.pop();
+ this.fragmentIndex++;
+
+ return this.currentFragment;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Constructors
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ public SimTraceWorkload(FlowSupplier supplier, TraceWorkload workload, long now) {
+ super(((FlowNode) supplier).getGraph());
+
+ this.snapshot = workload;
+ this.checkpointInterval = workload.getCheckpointInterval();
+ this.checkpointDuration = workload.getCheckpointDuration();
+ this.checkpointIntervalScaling = workload.getCheckpointIntervalScaling();
+ this.remainingFragments = new LinkedList<>(workload.getFragments());
+ this.fragmentIndex = 0;
+
+ final FlowGraph graph = ((FlowNode) supplier).getGraph();
+ graph.addEdge(this, supplier);
+
+ this.currentFragment = this.getNextFragment();
+ pushDemand(machineEdge, (float) this.currentFragment.cpuUsage());
+ this.startOfFragment = now;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Fragment related functionality
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ @Override
+ public long onUpdate(long now) {
+ long passedTime = getPassedTime(now);
+ long duration = this.currentFragment.duration();
+
+ // The current Fragment has not yet been finished, continue
+ if (passedTime < duration) {
+ return now + (duration - passedTime);
+ }
+
+ // Loop through fragments until the passed time is filled.
+ // We need a while loop to account for skipping of fragments.
+ while (passedTime >= duration) {
+ if (this.remainingFragments.isEmpty()) {
+ this.stopWorkload();
+ return Long.MAX_VALUE;
+ }
+
+ passedTime = passedTime - duration;
+
+ // get next Fragment
+ currentFragment = this.getNextFragment();
+ duration = currentFragment.duration();
+ }
+
+ // start new fragment
+ this.startOfFragment = now - passedTime;
+
+ // Change the cpu Usage to the new Fragment
+ pushDemand(machineEdge, (float) this.currentFragment.cpuUsage());
+
+ // Return the time when the current fragment will complete
+ return this.startOfFragment + duration;
+ }
+
+ @Override
+ public void stopWorkload() {
+ this.closeNode();
+
+ this.machineEdge = null;
+ this.remainingFragments = null;
+ this.currentFragment = null;
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // Checkpoint related functionality
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * SimTraceWorkload does not make a checkpoint, checkpointing is handled by SimChainWorkload
+ * TODO: Maybe add checkpoint models for SimTraceWorkload
+ */
+ @Override
+ void createCheckpointModel() {}
+
+ /**
+ * Create a new snapshot based on the current status of the workload.
+ * @param now
+ */
+ public void makeSnapshot(long now) {
+
+ // Check if fragments is empty
+
+ // Get remaining time of current fragment
+ long passedTime = getPassedTime(now);
+ long remainingTime = currentFragment.duration() - passedTime;
+
+ // Create a new fragment based on the current fragment and remaining duration
+ TraceFragment newFragment =
+ new TraceFragment(remainingTime, currentFragment.cpuUsage(), currentFragment.coreCount());
+
+ // Alter the snapshot by removing finished fragments
+ this.snapshot.removeFragments(this.fragmentIndex);
+ this.snapshot.addFirst(newFragment);
+
+ this.remainingFragments.addFirst(newFragment);
+
+ // Create and add a fragment for processing the snapshot process
+ // TODO: improve the implementation of cpuUsage and coreCount
+ TraceFragment snapshotFragment = new TraceFragment(this.checkpointDuration, 123456, 1);
+ this.remainingFragments.addFirst(snapshotFragment);
+
+ this.fragmentIndex = -1;
+ this.currentFragment = getNextFragment();
+ pushDemand(this.machineEdge, (float) this.currentFragment.cpuUsage());
+ this.startOfFragment = now;
+
+ this.invalidate();
+ }
+
+ /**
+ * Update the Fragments that are being used by the SimTraceWorkload
+ * @param newFragments
+ * @param offset
+ */
+ public void updateFragments(LinkedList<TraceFragment> newFragments, long offset) {
+ this.remainingFragments = newFragments;
+
+ // Start the first Fragment
+ this.currentFragment = this.remainingFragments.pop();
+ pushDemand(this.machineEdge, (float) this.currentFragment.cpuUsage());
+ this.startOfFragment = offset;
+
+ this.invalidate();
+ }
+
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+ // FlowGraph Related functionality
+ ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+ /**
+ * Handle updates in supply from the Virtual Machine
+ *
+ * @param supplierEdge
+ * @param newSupply
+ */
+ @Override
+ public void handleSupply(FlowEdge supplierEdge, float newSupply) {
+ if (newSupply == this.currentSupply) {
+ return;
+ }
+
+ this.currentSupply = newSupply;
+ }
+
+ /**
+ * Push a new demand to the Virtual Machine
+ *
+ * @param supplierEdge
+ * @param newDemand
+ */
+ @Override
+ public void pushDemand(FlowEdge supplierEdge, float newDemand) {
+ if (newDemand == this.currentDemand) {
+ return;
+ }
+
+ this.currentDemand = newDemand;
+ this.machineEdge.pushDemand(newDemand);
+ }
+
+ /**
+ * Add the connection to the Virtual Machine
+ *
+ * @param supplierEdge
+ */
+ @Override
+ public void addSupplierEdge(FlowEdge supplierEdge) {
+ this.machineEdge = supplierEdge;
+ }
+
+ /**
+ * Handle the removal of the connection to the Virtual Machine
+ * When the connection to the Virtual Machine is removed, the SimTraceWorkload is removed
+ *
+ * @param supplierEdge
+ */
+ @Override
+ public void removeSupplierEdge(FlowEdge supplierEdge) {
+ this.stopWorkload();
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimWorkload.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimWorkload.java
index f4f3ff58..b5c89941 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimWorkload.java
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimWorkload.java
@@ -22,7 +22,9 @@
package org.opendc.simulator.compute.workload;
-import org.opendc.simulator.compute.SimMachineContext;
+import org.opendc.simulator.engine.FlowConsumer;
+import org.opendc.simulator.engine.FlowGraph;
+import org.opendc.simulator.engine.FlowNode;
/**
* A model that characterizes the runtime behavior of some particular workload.
@@ -31,35 +33,33 @@ import org.opendc.simulator.compute.SimMachineContext;
* Workloads are stateful objects that may be paused and resumed at a later moment. As such, be careful when using the
* same {@link SimWorkload} from multiple contexts.
*/
-public interface SimWorkload {
+public abstract class SimWorkload extends FlowNode implements FlowConsumer {
/**
- * This method is invoked when the workload is started.
+ * Construct a new {@link FlowNode} instance.
*
- * @param ctx The execution context in which the machine runs.
+ * @param parentGraph The {@link FlowGraph} this stage belongs to.
*/
- void onStart(SimMachineContext ctx);
+ public SimWorkload(FlowGraph parentGraph) {
+ super(parentGraph);
+ }
/**
* This method is invoked when the workload is stopped.
- *
- * @param ctx The execution context in which the machine runs.
*/
- void onStop(SimMachineContext ctx);
+ public abstract void stopWorkload();
/**
* Create a snapshot of this workload.
*/
- void makeSnapshot(long now);
-
- SimWorkload getSnapshot();
+ public abstract void makeSnapshot(long now);
- void createCheckpointModel();
+ public abstract Workload getSnapshot();
- long getCheckpointInterval();
+ abstract void createCheckpointModel();
- long getCheckpointDuration();
+ abstract long getCheckpointInterval();
- double getCheckpointIntervalScaling();
+ abstract long getCheckpointDuration();
- void setOffset(long now);
+ abstract double getCheckpointIntervalScaling();
}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimWorkloads.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimWorkloads.java
deleted file mode 100644
index 34202945..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimWorkloads.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (c) 2022 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 java.time.Duration;
-
-/**
- * Helper methods for constructing {@link SimWorkload}s.
- */
-public class SimWorkloads {
- private SimWorkloads() {}
-
- /**
- * Create a {@link SimWorkload} that executes a specified number of floating point operations (FLOPs) at the given
- * utilization.
- *
- * @param flops The number of floating point operations to perform for this task in MFLOPs.
- * @param utilization The CPU utilization of the workload.
- */
- public static SimWorkload flops(long flops, double utilization) {
- return new SimFlopsWorkload(flops, utilization);
- }
-
- /**
- * Create a {@link SimWorkload} that consumes the CPU resources for a specified duration at the given utilization.
- *
- * @param duration The duration of the workload in milliseconds.
- * @param utilization The CPU utilization of the workload.
- */
- public static SimWorkload runtime(long duration, double utilization) {
- return runtime(duration, utilization, 0, 0);
- }
-
- /**
- * Create a {@link SimWorkload} that consumes the CPU resources for a specified duration at the given utilization.
- *
- * @param duration The duration of the workload in milliseconds.
- * @param utilization The CPU utilization of the workload.
- */
- public static SimWorkload runtime(
- long duration, double utilization, long checkpointInterval, long checkpointDuration) {
- return new SimRuntimeWorkload(duration, utilization, checkpointInterval, checkpointDuration);
- }
-
- /**
- * Create a {@link SimWorkload} that consumes the CPU resources for a specified duration at the given utilization.
- *
- * @param duration The duration of the workload.
- * @param utilization The CPU utilization of the workload.
- */
- public static SimWorkload runtime(
- Duration duration, double utilization, long checkpointInterval, long checkpointDuration) {
- return runtime(duration.toMillis(), utilization, checkpointInterval, checkpointDuration);
- }
-
- /**
- * Chain the specified <code>workloads</code> into a single {@link SimWorkload}.
- */
- public static SimWorkload chain(SimWorkload... workloads) {
- return new SimChainWorkload(workloads);
- }
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimTraceFragment.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/TraceFragment.java
index 374e9732..550c2135 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimTraceFragment.java
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/TraceFragment.java
@@ -22,9 +22,9 @@
package org.opendc.simulator.compute.workload;
-public record SimTraceFragment(long duration, double cpuUsage, int coreCount) {
+public record TraceFragment(long duration, double cpuUsage, int coreCount) {
- public SimTraceFragment(long start, long duration, double cpuUsage, int coreCount) {
+ public TraceFragment(long start, long duration, double cpuUsage, int coreCount) {
this(duration, cpuUsage, coreCount);
}
}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/TraceWorkload.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/TraceWorkload.java
new file mode 100644
index 00000000..115689df
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/TraceWorkload.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2024 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package org.opendc.simulator.compute.workload;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.opendc.simulator.engine.FlowSupplier;
+
+public class TraceWorkload implements Workload {
+ private ArrayList<TraceFragment> fragments;
+ private final long checkpointInterval;
+ private final long checkpointDuration;
+ private final double checkpointIntervalScaling;
+
+ public TraceWorkload(
+ ArrayList<TraceFragment> fragments,
+ long checkpointInterval,
+ long checkpointDuration,
+ double checkpointIntervalScaling) {
+ this.fragments = fragments;
+ this.checkpointInterval = checkpointInterval;
+ this.checkpointDuration = checkpointDuration;
+ this.checkpointIntervalScaling = checkpointIntervalScaling;
+ }
+
+ public ArrayList<TraceFragment> getFragments() {
+ return fragments;
+ }
+
+ @Override
+ public long getCheckpointInterval() {
+ return checkpointInterval;
+ }
+
+ @Override
+ public long getCheckpointDuration() {
+ return checkpointDuration;
+ }
+
+ @Override
+ public double getCheckpointIntervalScaling() {
+ return checkpointIntervalScaling;
+ }
+
+ public void removeFragments(int numberOfFragments) {
+ if (numberOfFragments <= 0) {
+ return;
+ }
+ this.fragments.subList(0, numberOfFragments).clear();
+ }
+
+ public void addFirst(TraceFragment fragment) {
+ this.fragments.add(0, fragment);
+ }
+
+ @Override
+ public SimWorkload startWorkload(FlowSupplier supplier, long now) {
+ return new SimTraceWorkload(supplier, this, now);
+ }
+
+ public static Builder builder() {
+ return builder(0L, 0L, 0L);
+ }
+
+ public static Builder builder(long checkpointInterval, long checkpointDuration, double checkpointIntervalScaling) {
+ return new Builder(checkpointInterval, checkpointDuration, checkpointIntervalScaling);
+ }
+
+ /**
+ * Construct a {@link TraceWorkload} from the specified fragments.
+ *
+ * @param fragments The array of fragments to construct the trace from.
+ */
+ public static TraceWorkload ofFragments(TraceFragment... fragments) {
+ final Builder builder = builder();
+
+ for (TraceFragment fragment : fragments) {
+ builder.add(fragment.duration(), fragment.cpuUsage(), fragment.coreCount());
+ }
+
+ return builder.build();
+ }
+
+ /**
+ * Construct a {@link TraceWorkload} from the specified fragments.
+ *
+ * @param fragments The fragments to construct the trace from.
+ */
+ public static TraceWorkload ofFragments(List<TraceFragment> fragments) {
+ final Builder builder = builder();
+
+ for (TraceFragment fragment : fragments) {
+ builder.add(fragment.duration(), fragment.cpuUsage(), fragment.coreCount());
+ }
+
+ return builder.build();
+ }
+
+ public static final class Builder {
+ private final ArrayList<TraceFragment> fragments;
+ private final long checkpointInterval;
+ private final long checkpointDuration;
+ private final double checkpointIntervalScaling;
+
+ /**
+ * Construct a new {@link Builder} instance.
+ */
+ private Builder(long checkpointInterval, long checkpointDuration, double checkpointIntervalScaling) {
+ this.fragments = new ArrayList<>();
+ this.checkpointInterval = checkpointInterval;
+ this.checkpointDuration = checkpointDuration;
+ this.checkpointIntervalScaling = checkpointIntervalScaling;
+ }
+
+ /**
+ * Add a fragment to the trace.
+ *
+ * @param duration The timestamp at which the fragment ends (in epoch millis).
+ * @param usage The CPU usage at this fragment.
+ * @param cores The number of cores used during this fragment.
+ */
+ public void add(long duration, double usage, int cores) {
+ fragments.add(0, new TraceFragment(duration, usage, cores));
+ }
+
+ /**
+ * Build the {@link TraceWorkload} instance.
+ */
+ public TraceWorkload build() {
+ return new TraceWorkload(
+ this.fragments, this.checkpointInterval, this.checkpointDuration, this.checkpointIntervalScaling);
+ }
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-power/build.gradle.kts b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/Workload.java
index ea36ce75..cd34921a 100644
--- a/opendc-simulator/opendc-simulator-power/build.gradle.kts
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/Workload.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 AtLarge Research
+ * Copyright (c) 2024 AtLarge Research
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -20,15 +20,17 @@
* SOFTWARE.
*/
-description = "Library for simulating datacenter power components"
+package org.opendc.simulator.compute.workload;
-plugins {
- `kotlin-library-conventions`
-}
+import org.opendc.simulator.engine.FlowSupplier;
+
+public interface Workload {
+
+ long getCheckpointInterval();
+
+ long getCheckpointDuration();
-dependencies {
- api(projects.opendcSimulator.opendcSimulatorFlow)
- implementation(projects.opendcSimulator.opendcSimulatorCore)
+ double getCheckpointIntervalScaling();
- testImplementation(libs.slf4j.simple)
+ SimWorkload startWorkload(FlowSupplier supplier, long now);
}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/Coroutines.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/Coroutines.kt
index 63af2048..ad69a3d6 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/Coroutines.kt
+++ b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/Coroutines.kt
@@ -23,12 +23,13 @@
package org.opendc.simulator.compute
import kotlinx.coroutines.suspendCancellableCoroutine
-import org.opendc.simulator.compute.workload.SimWorkload
+import org.opendc.simulator.compute.machine.SimMachine
+import org.opendc.simulator.compute.workload.TraceWorkload
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException
/**
- * Run the specified [SimWorkload] on this machine and suspend execution util [workload] has finished.
+ * Run the specified [SimWorkloadNew] on this machine and suspend execution util [workload] has finished.
*
* @param workload The workload to start on the machine.
* @param meta The metadata to pass to the workload.
@@ -36,13 +37,13 @@ import kotlin.coroutines.resumeWithException
* @throws IllegalStateException if a workload is already active on the machine or if the machine is closed.
*/
public suspend fun SimMachine.runWorkload(
- workload: SimWorkload,
+ workload: TraceWorkload,
meta: Map<String, Any> = emptyMap(),
) {
return suspendCancellableCoroutine { cont ->
- cont.invokeOnCancellation { this@runWorkload.cancel() }
+ cont.invokeOnCancellation { this@runWorkload.shutdown() }
- startWorkload(workload, meta) { cause ->
+ startWorkload(workload) { cause ->
if (cause != null) cont.resumeWithException(cause) else cont.resume(Unit)
}
}
diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimMachineTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimMachineTest.kt
index be6d289c..2b6a922e 100644
--- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimMachineTest.kt
+++ b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/SimMachineTest.kt
@@ -22,33 +22,17 @@
package org.opendc.simulator.compute
-import io.mockk.every
-import io.mockk.mockk
-import kotlinx.coroutines.CancellationException
-import kotlinx.coroutines.cancel
-import kotlinx.coroutines.coroutineScope
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.yield
-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.assertThrows
-import org.opendc.simulator.compute.device.SimNetworkAdapter
-import org.opendc.simulator.compute.model.Cpu
-import org.opendc.simulator.compute.model.MachineModel
-import org.opendc.simulator.compute.model.MemoryUnit
-import org.opendc.simulator.compute.model.NetworkAdapter
-import org.opendc.simulator.compute.model.StorageDevice
-import org.opendc.simulator.compute.power.CpuPowerModels
-import org.opendc.simulator.compute.workload.SimTrace
-import org.opendc.simulator.compute.workload.SimWorkload
-import org.opendc.simulator.compute.workload.SimWorkloads
-import org.opendc.simulator.flow2.FlowEngine
-import org.opendc.simulator.flow2.source.SimpleFlowSource
+import org.opendc.simulator.compute.cpu.CpuPowerModels
+import org.opendc.simulator.compute.machine.SimMachine
+import org.opendc.simulator.compute.models.CpuModel
+import org.opendc.simulator.compute.models.MachineModel
+import org.opendc.simulator.compute.models.MemoryUnit
+import org.opendc.simulator.compute.workload.TraceWorkload
+import org.opendc.simulator.engine.FlowEngine
import org.opendc.simulator.kotlin.runSimulation
-import org.opendc.simulator.network.SimNetworkSink
-import org.opendc.simulator.power.SimPowerSource
import java.util.concurrent.ThreadLocalRandom
/**
@@ -61,529 +45,390 @@ class SimMachineTest {
fun setUp() {
machineModel =
MachineModel(
- Cpu(
+ CpuModel(
0,
2,
- 1000.0,
+ 1000.0f,
"Intel",
"Xeon",
"amd64",
),
MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000 * 4),
- listOf(NetworkAdapter("Mellanox", "ConnectX-5", 25000.0)),
- listOf(StorageDevice("Samsung", "EVO", 1000.0, 250.0, 250.0)),
)
}
// @Test
- fun testFlopsWorkload() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine =
- SimBareMetalMachine.create(
- graph,
- machineModel,
- )
-
- machine.runWorkload(SimWorkloads.flops(2_000, 1.0))
-
- // Two cores execute 1000 MFlOps per second (1000 ms)
- assertEquals(1000, timeSource.millis())
- }
+// fun testFlopsWorkload() =
+// runSimulation {
+// val engine = FlowEngine.create(dispatcher)
+// val graph = engine.newGraph()
+//
+// val machine =
+// SimBareMetalMachine.create(
+// graph,
+// machineModel,
+// )
+//
+// machine.runWorkload(SimWorkloads.flops(2_000, 1.0))
+//
+// // Two cores execute 1000 MFlOps per second (1000 ms)
+// assertEquals(1000, timeSource.millis())
+// }
@Test
fun testTraceWorkload() =
runSimulation {
val random = ThreadLocalRandom.current()
- val builder = SimTrace.builder()
- repeat(1000000) {
-// val timestamp = it.toLong() * 1000
-// val deadline = timestamp + 1000
+ val builder = TraceWorkload.builder()
+ repeat(100) {
builder.add(1000, random.nextDouble(0.0, 4500.0), 1)
}
- val trace = builder.build()
-
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
- val machine =
- SimBareMetalMachine.create(
- graph,
- machineModel,
- )
+ val traceWorkload = builder.build()
- machine.runWorkload(trace.createWorkload(0))
-
- // Two cores execute 1000 MFlOps per second (1000 ms)
- assertEquals(1000000000, timeSource.millis())
- }
-
-// @Test
- fun testDualSocketMachine() =
- runSimulation {
val engine = FlowEngine.create(dispatcher)
val graph = engine.newGraph()
-
- val cpuNode = machineModel.cpu
- val machineModel =
- MachineModel(
- List(cpuNode.coreCount * 2) {
- Cpu(
- it,
- cpuNode.coreCount,
- 1000.0,
- )
- },
- MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000 * 4),
- )
- val machine =
- SimBareMetalMachine.create(
+ val simMachine =
+ SimMachine(
graph,
machineModel,
- )
-
- machine.runWorkload(SimWorkloads.flops(2_000, 1.0))
-
- // Two sockets with two cores execute 2000 MFlOps per second (500 ms)
- assertEquals(500, timeSource.millis())
- }
-
- @Test
- fun testPower() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
- val machine =
- SimBareMetalMachine.create(
- graph,
- machineModel,
- SimPsuFactories.simple(CpuPowerModels.linear(100.0, 50.0)),
- )
- val source = SimPowerSource(graph, 1000.0f)
- source.connect(machine.psu)
-
- coroutineScope {
- launch { machine.runWorkload(SimWorkloads.flops(2_000, 1.0)) }
-
- yield()
- assertAll(
- { assertEquals(100.0, machine.psu.powerDraw) },
- { assertEquals(100.0f, source.powerDraw) },
- )
- }
- }
-
- @Test
- fun testCapacityClamp() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine =
- SimBareMetalMachine.create(
- graph,
- machineModel,
- )
-
- machine.runWorkload(
- object : SimWorkload {
- override fun onStart(ctx: SimMachineContext) {
- val cpu = ctx.cpu
-
- cpu.frequency = (cpu.cpuModel.totalCapacity + 1000.0)
- assertEquals(cpu.cpuModel.totalCapacity, cpu.frequency)
- cpu.frequency = -1.0
- assertEquals(0.0, cpu.frequency)
-
- ctx.shutdown()
- }
-
- override fun setOffset(now: Long) {}
-
- override fun onStop(ctx: SimMachineContext) {}
-
- override fun makeSnapshot(now: Long) {
- }
-
- override fun getSnapshot(): SimWorkload = this
-
- override fun createCheckpointModel() {}
-
- override fun getCheckpointInterval(): Long {
- return -1
- }
-
- override fun getCheckpointDuration(): Long {
- return -1
- }
-
- override fun getCheckpointIntervalScaling(): Double {
- return -1.0
- }
- },
- )
- }
-
- @Test
- fun testMemory() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine =
- SimBareMetalMachine.create(
- graph,
- machineModel,
- )
-
- machine.runWorkload(
- object : SimWorkload {
- override fun onStart(ctx: SimMachineContext) {
- assertEquals(32_000 * 4.0, ctx.memory.capacity)
- ctx.shutdown()
- }
-
- override fun setOffset(now: Long) {}
-
- override fun onStop(ctx: SimMachineContext) {}
-
- override fun makeSnapshot(now: Long) {}
-
- override fun getSnapshot(): SimWorkload = this
-
- override fun createCheckpointModel() {}
-
- override fun getCheckpointInterval(): Long {
- return -1
- }
-
- override fun getCheckpointDuration(): Long {
- return -1
- }
-
- override fun getCheckpointIntervalScaling(): Double {
- return -1.0
- }
- },
- )
- }
-
- @Test
- fun testMemoryUsage() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine =
- SimBareMetalMachine.create(
- graph,
- machineModel,
- )
-
- machine.runWorkload(
- object : SimWorkload {
- override fun onStart(ctx: SimMachineContext) {
- val source = SimpleFlowSource(ctx.graph, ctx.memory.capacity.toFloat(), 1.0f) { ctx.shutdown() }
- ctx.graph.connect(source.output, ctx.memory.input)
- }
-
- override fun setOffset(now: Long) {}
-
- override fun onStop(ctx: SimMachineContext) {}
-
- override fun makeSnapshot(now: Long) {
- }
-
- override fun getSnapshot(): SimWorkload = this
-
- override fun createCheckpointModel() {}
-
- override fun getCheckpointInterval(): Long {
- return -1
- }
-
- override fun getCheckpointDuration(): Long {
- return -1
- }
-
- override fun getCheckpointIntervalScaling(): Double {
- return -1.0
- }
- },
- )
-
- assertEquals(1000, timeSource.millis())
- }
-
- @Test
- fun testNetUsage() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine =
- SimBareMetalMachine.create(
- graph,
- machineModel,
- )
-
- val adapter = (machine.peripherals[0] as SimNetworkAdapter)
- adapter.connect(SimNetworkSink(graph, adapter.bandwidth.toFloat()))
-
- machine.runWorkload(
- object : SimWorkload {
- override fun onStart(ctx: SimMachineContext) {
- val iface = ctx.networkInterfaces[0]
- val source =
- SimpleFlowSource(ctx.graph, 800.0f, 0.8f) {
- ctx.shutdown()
- it.close()
- }
- ctx.graph.connect(source.output, iface.tx)
- }
-
- override fun setOffset(now: Long) {}
-
- override fun onStop(ctx: SimMachineContext) {}
-
- override fun makeSnapshot(now: Long) {
- }
-
- override fun getSnapshot(): SimWorkload = this
-
- override fun createCheckpointModel() {}
-
- override fun getCheckpointInterval(): Long {
- return -1
- }
-
- override fun getCheckpointDuration(): Long {
- return -1
- }
-
- override fun getCheckpointIntervalScaling(): Double {
- return -1.0
- }
- },
- )
-
- assertEquals(40, timeSource.millis())
- }
-
- @Test
- fun testDiskReadUsage() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine =
- SimBareMetalMachine.create(
- graph,
- machineModel,
- )
-
- machine.runWorkload(
- object : SimWorkload {
- override fun onStart(ctx: SimMachineContext) {
- val disk = ctx.storageInterfaces[0]
- val source = SimpleFlowSource(ctx.graph, 800.0f, 0.8f) { ctx.shutdown() }
- ctx.graph.connect(source.output, disk.read)
- }
-
- override fun setOffset(now: Long) {}
-
- override fun onStop(ctx: SimMachineContext) {}
-
- override fun makeSnapshot(now: Long) {}
-
- override fun getSnapshot(): SimWorkload = this
-
- override fun createCheckpointModel() {}
-
- override fun getCheckpointInterval(): Long {
- return -1
- }
-
- override fun getCheckpointDuration(): Long {
- return -1
- }
-
- override fun getCheckpointIntervalScaling(): Double {
- return -1.0
- }
- },
- )
-
- assertEquals(4000, timeSource.millis())
- }
-
- @Test
- fun testDiskWriteUsage() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine =
- SimBareMetalMachine.create(
- graph,
- machineModel,
- )
-
- machine.runWorkload(
- object : SimWorkload {
- override fun onStart(ctx: SimMachineContext) {
- val disk = ctx.storageInterfaces[0]
- val source = SimpleFlowSource(ctx.graph, 800.0f, 0.8f) { ctx.shutdown() }
- ctx.graph.connect(source.output, disk.write)
- }
-
- override fun setOffset(now: Long) {}
-
- override fun onStop(ctx: SimMachineContext) {}
-
- override fun makeSnapshot(now: Long) {}
-
- override fun getSnapshot(): SimWorkload = this
-
- override fun createCheckpointModel() {}
-
- override fun getCheckpointInterval(): Long {
- return -1
- }
-
- override fun getCheckpointDuration(): Long {
- return -1
- }
-
- override fun getCheckpointIntervalScaling(): Double {
- return -1.0
- }
- },
- )
-
- assertEquals(4000, timeSource.millis())
- }
-
- @Test
- fun testCancellation() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine =
- SimBareMetalMachine.create(
- graph,
- machineModel,
- )
-
- try {
- coroutineScope {
- launch { machine.runWorkload(SimWorkloads.flops(2_000, 1.0)) }
- cancel()
- }
- } catch (_: CancellationException) {
- // Ignore
- }
-
- assertEquals(0, timeSource.millis())
- }
-
- @Test
- fun testConcurrentRuns() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine =
- SimBareMetalMachine.create(
- graph,
- machineModel,
- )
-
- coroutineScope {
- launch {
- machine.runWorkload(SimWorkloads.flops(2_000, 1.0))
+ CpuPowerModels.constant(0.0),
+ ) { cause ->
}
- assertThrows<IllegalStateException> {
- machine.runWorkload(SimWorkloads.flops(2_000, 1.0))
+ val virtualMachine =
+ simMachine.startWorkload(traceWorkload) { cause ->
+ assertEquals(100000, timeSource.millis())
}
- }
- }
-
- @Test
- fun testCatchStartFailure() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine =
- SimBareMetalMachine.create(
- graph,
- machineModel,
- )
-
- val workload = mockk<SimWorkload>()
- every { workload.onStart(any()) } throws IllegalStateException()
-
- assertThrows<IllegalStateException> { machine.runWorkload(workload) }
- }
-
- @Test
- fun testCatchStopFailure() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine =
- SimBareMetalMachine.create(
- graph,
- machineModel,
- )
-
- val workload = mockk<SimWorkload>()
- every { workload.onStart(any()) } answers { (it.invocation.args[0] as SimMachineContext).shutdown() }
- every { workload.onStop(any()) } throws IllegalStateException()
-
- assertThrows<IllegalStateException> { machine.runWorkload(workload) }
- }
-
- @Test
- fun testCatchShutdownFailure() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine =
- SimBareMetalMachine.create(
- graph,
- machineModel,
- )
-
- val workload = mockk<SimWorkload>()
- every { workload.onStart(any()) } answers { (it.invocation.args[0] as SimMachineContext).shutdown(IllegalStateException()) }
- assertThrows<IllegalStateException> { machine.runWorkload(workload) }
+ // Two cores execute 1000 MFlOps per second (1000 ms)
}
- @Test
- fun testCatchNestedFailure() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine =
- SimBareMetalMachine.create(
- graph,
- machineModel,
- )
-
- val workload = mockk<SimWorkload>()
- every { workload.onStart(any()) } answers { (it.invocation.args[0] as SimMachineContext).shutdown(IllegalStateException()) }
- every { workload.onStop(any()) } throws IllegalStateException()
-
- val exc = assertThrows<IllegalStateException> { machine.runWorkload(workload) }
- assertEquals(1, exc.cause!!.suppressedExceptions.size)
- }
+// @Test
+// fun testDualSocketMachine() =
+// runSimulation {
+// val engine = FlowEngine.create(dispatcher)
+// val graph = engine.newGraph()
+//
+// val cpuNode = machineModel.cpu
+// val machineModel =
+// MachineModel(
+// List(cpuNode.coreCount * 2) {
+// CpuModel(
+// it,
+// cpuNode.coreCount,
+// 1000.0,
+// )
+// },
+// MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000 * 4),
+// )
+// val machine =
+// SimBareMetalMachine.create(
+// graph,
+// machineModel,
+// CpuPowerModels.constant(0.0)
+// )
+//
+// machine.runWorkload(SimWorkloads.flops(2_000, 1.0))
+//
+// // Two sockets with two cores execute 2000 MFlOps per second (500 ms)
+// assertEquals(500, timeSource.millis())
+// }
+//
+// // @Test
+// // fun testPower() =
+// // runSimulation {
+// // val engine = FlowEngine.create(dispatcher)
+// // val graph = engine.newGraph()
+// // val machine =
+// // SimBareMetalMachine.create(
+// // graph,
+// // machineModel,
+// // CpuPowerModels.linear(100.0, 50.0),
+// // )
+// // val source = SimPowerSource(graph, 1000.0f)
+// // source.connect(machine.psu)
+// //
+// // coroutineScope {
+// // launch { machine.runWorkload(SimWorkloads.flops(2_000, 1.0)) }
+// //
+// // yield()
+// // assertAll(
+// // { assertEquals(100.0, machine.psu.powerDraw) },
+// // { assertEquals(100.0f, source.powerDraw) },
+// // )
+// // }
+// // }
+//
+// @Test
+// fun testCapacityClamp() =
+// runSimulation {
+// val engine = FlowEngine.create(dispatcher)
+// val graph = engine.newGraph()
+//
+// val machine =
+// SimBareMetalMachine.create(
+// graph,
+// machineModel,
+// CpuPowerModels.constant(0.0)
+// )
+//
+// machine.runWorkload(
+// object : SimWorkload {
+// override fun onStart(ctx: SimMachineContext) {
+// val cpu = ctx.cpu
+//
+// cpu.frequency = (cpu.cpuModel.totalCapacity + 1000.0)
+// assertEquals(cpu.cpuModel.totalCapacity, cpu.frequency)
+// cpu.frequency = -1.0
+// assertEquals(0.0, cpu.frequency)
+//
+// ctx.shutdown()
+// }
+//
+// override fun setOffset(now: Long) {}
+//
+// override fun onStop(ctx: SimMachineContext) {}
+//
+// override fun makeSnapshot(now: Long) {
+// }
+//
+// override fun getSnapshot(): SimWorkload = this
+//
+// override fun createCheckpointModel() {}
+//
+// override fun getCheckpointInterval(): Long {
+// return -1
+// }
+//
+// override fun getCheckpointDuration(): Long {
+// return -1
+// }
+//
+// override fun getCheckpointIntervalScaling(): Double {
+// return -1.0
+// }
+// },
+// )
+// }
+//
+// @Test
+// fun testMemory() =
+// runSimulation {
+// val engine = FlowEngine.create(dispatcher)
+// val graph = engine.newGraph()
+//
+// val machine =
+// SimBareMetalMachine.create(
+// graph,
+// machineModel,
+// CpuPowerModels.constant(0.0)
+// )
+//
+// machine.runWorkload(
+// object : SimWorkload {
+// override fun onStart(ctx: SimMachineContext) {
+// assertEquals(32_000 * 4.0, ctx.memory.capacity)
+// ctx.shutdown()
+// }
+//
+// override fun setOffset(now: Long) {}
+//
+// override fun onStop(ctx: SimMachineContext) {}
+//
+// override fun makeSnapshot(now: Long) {}
+//
+// override fun getSnapshot(): SimWorkload = this
+//
+// override fun createCheckpointModel() {}
+//
+// override fun getCheckpointInterval(): Long {
+// return -1
+// }
+//
+// override fun getCheckpointDuration(): Long {
+// return -1
+// }
+//
+// override fun getCheckpointIntervalScaling(): Double {
+// return -1.0
+// }
+// },
+// )
+// }
+//
+// @Test
+// fun testMemoryUsage() =
+// runSimulation {
+// val engine = FlowEngine.create(dispatcher)
+// val graph = engine.newGraph()
+//
+// val machine =
+// SimBareMetalMachine.create(
+// graph,
+// machineModel,
+// CpuPowerModels.constant(0.0)
+// )
+//
+// machine.runWorkload(
+// object : SimWorkload {
+// override fun onStart(ctx: SimMachineContext) {
+// val source = SimpleFlowSource(ctx.graph, ctx.memory.capacity.toFloat(), 1.0f) { ctx.shutdown() }
+// ctx.graph.connect(source.output, ctx.memory.input)
+// }
+//
+// override fun setOffset(now: Long) {}
+//
+// override fun onStop(ctx: SimMachineContext) {}
+//
+// override fun makeSnapshot(now: Long) {
+// }
+//
+// override fun getSnapshot(): SimWorkload = this
+//
+// override fun createCheckpointModel() {}
+//
+// override fun getCheckpointInterval(): Long {
+// return -1
+// }
+//
+// override fun getCheckpointDuration(): Long {
+// return -1
+// }
+//
+// override fun getCheckpointIntervalScaling(): Double {
+// return -1.0
+// }
+// },
+// )
+//
+// assertEquals(1000, timeSource.millis())
+// }
+//
+// @Test
+// fun testCancellation() =
+// runSimulation {
+// val engine = FlowEngine.create(dispatcher)
+// val graph = engine.newGraph()
+//
+// val machine =
+// SimBareMetalMachine.create(
+// graph,
+// machineModel,
+// CpuPowerModels.constant(0.0)
+// )
+//
+// try {
+// coroutineScope {
+// launch { machine.runWorkload(SimWorkloads.flops(2_000, 1.0)) }
+// cancel()
+// }
+// } catch (_: CancellationException) {
+// // Ignore
+// }
+//
+// assertEquals(0, timeSource.millis())
+// }
+//
+// @Test
+// fun testConcurrentRuns() =
+// runSimulation {
+// val engine = FlowEngine.create(dispatcher)
+// val graph = engine.newGraph()
+//
+// val machine =
+// SimBareMetalMachine.create(
+// graph,
+// machineModel,
+// CpuPowerModels.constant(0.0)
+// )
+//
+// coroutineScope {
+// launch {
+// machine.runWorkload(SimWorkloads.flops(2_000, 1.0))
+// }
+//
+// assertThrows<IllegalStateException> {
+// machine.runWorkload(SimWorkloads.flops(2_000, 1.0))
+// }
+// }
+// }
+//
+// @Test
+// fun testCatchStartFailure() =
+// runSimulation {
+// val engine = FlowEngine.create(dispatcher)
+// val graph = engine.newGraph()
+//
+// val machine =
+// SimBareMetalMachine.create(
+// graph,
+// machineModel,
+// CpuPowerModels.constant(0.0)
+// )
+//
+// val workload = mockk<SimWorkload>()
+// every { workload.onStart(any()) } throws IllegalStateException()
+//
+// assertThrows<IllegalStateException> { machine.runWorkload(workload) }
+// }
+//
+// @Test
+// fun testCatchStopFailure() =
+// runSimulation {
+// val engine = FlowEngine.create(dispatcher)
+// val graph = engine.newGraph()
+//
+// val machine =
+// SimBareMetalMachine.create(
+// graph,
+// machineModel,
+// CpuPowerModels.constant(0.0)
+// )
+//
+// val workload = mockk<SimWorkload>()
+// every { workload.onStart(any()) } answers { (it.invocation.args[0] as SimMachineContext).shutdown() }
+// every { workload.onStop(any()) } throws IllegalStateException()
+//
+// assertThrows<IllegalStateException> { machine.runWorkload(workload) }
+// }
+//
+// @Test
+// fun testCatchShutdownFailure() =
+// runSimulation {
+// val engine = FlowEngine.create(dispatcher)
+// val graph = engine.newGraph()
+//
+// val machine =
+// SimBareMetalMachine.create(
+// graph,
+// machineModel,
+// CpuPowerModels.constant(0.0)
+// )
+//
+// val workload = mockk<SimWorkload>()
+// every { workload.onStart(any()) } answers { (it.invocation.args[0] as SimMachineContext).shutdown(IllegalStateException()) }
+//
+// assertThrows<IllegalStateException> { machine.runWorkload(workload) }
+// }
+//
+// @Test
+// fun testCatchNestedFailure() =
+// runSimulation {
+// val engine = FlowEngine.create(dispatcher)
+// val graph = engine.newGraph()
+//
+// val machine =
+// SimBareMetalMachine.create(
+// graph,
+// machineModel,
+// CpuPowerModels.constant(0.0)
+// )
+//
+// val workload = mockk<SimWorkload>()
+// every { workload.onStart(any()) } answers { (it.invocation.args[0] as SimMachineContext).shutdown(IllegalStateException()) }
+// every { workload.onStop(any()) } throws IllegalStateException()
+//
+// val exc = assertThrows<IllegalStateException> { machine.runWorkload(workload) }
+// assertEquals(1, exc.cause!!.suppressedExceptions.size)
+// }
}
diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisorTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisorTest.kt
deleted file mode 100644
index 6cebc46f..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimFairShareHypervisorTest.kt
+++ /dev/null
@@ -1,269 +0,0 @@
-/*
- * Copyright (c) 2021 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.kernel
-
-import kotlinx.coroutines.coroutineScope
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.yield
-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.junit.jupiter.api.assertDoesNotThrow
-import org.opendc.simulator.compute.SimBareMetalMachine
-import org.opendc.simulator.compute.kernel.cpufreq.ScalingGovernors
-import org.opendc.simulator.compute.kernel.interference.VmInterferenceModel
-import org.opendc.simulator.compute.model.Cpu
-import org.opendc.simulator.compute.model.MachineModel
-import org.opendc.simulator.compute.model.MemoryUnit
-import org.opendc.simulator.compute.runWorkload
-import org.opendc.simulator.compute.workload.SimTrace
-import org.opendc.simulator.compute.workload.SimTraceFragment
-import org.opendc.simulator.flow2.FlowEngine
-import org.opendc.simulator.flow2.mux.FlowMultiplexerFactory
-import org.opendc.simulator.kotlin.runSimulation
-import java.util.SplittableRandom
-
-/**
- * Test suite for the [SimHypervisor] class.
- */
-internal class SimFairShareHypervisorTest {
- private lateinit var model: MachineModel
-
- @BeforeEach
- fun setUp() {
- model =
- MachineModel(
- Cpu(
- 0,
- 1,
- 3200.0,
- "Intel",
- "Xeon",
- "amd64",
- ),
- // memory
- MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000 * 4),
- )
- }
-
- /**
- * Test overcommitting of resources via the hypervisor with a single VM.
- */
- @Test
- fun testOvercommittedSingle() =
- runSimulation {
- val duration = 5 * 60L
- val workloadA =
- SimTrace.ofFragments(
- SimTraceFragment(0, duration * 1000, 28.0, 1),
- SimTraceFragment(duration * 1000, duration * 1000, 3500.0, 1),
- SimTraceFragment(duration * 2000, duration * 1000, 0.0, 1),
- SimTraceFragment(duration * 3000, duration * 1000, 183.0, 1),
- ).createWorkload(0)
-
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine = SimBareMetalMachine.create(graph, model)
- val hypervisor =
- SimHypervisor.create(
- FlowMultiplexerFactory.maxMinMultiplexer(),
- SplittableRandom(0L),
- ScalingGovernors.performance(),
- )
-
- launch { machine.runWorkload(hypervisor) }
- yield()
-
- val vm = hypervisor.newMachine(model)
- vm.runWorkload(workloadA)
-
- yield()
- machine.cancel()
-
- assertAll(
- { assertEquals(319781, hypervisor.counters.cpuActiveTime, "Active time does not match") },
- { assertEquals(880219, hypervisor.counters.cpuIdleTime, "Idle time does not match") },
- { assertEquals(28125, hypervisor.counters.cpuStealTime, "Steal time does not match") },
- { assertEquals(1200000, timeSource.millis()) { "Current time is correct" } },
- )
- }
-
- /**
- * Test overcommitting of resources via the hypervisor with two VMs.
- */
- @Test
- fun testOvercommittedDual() =
- runSimulation {
- val duration = 5 * 60L
- val workloadA =
- SimTrace.ofFragments(
- SimTraceFragment(0, duration * 1000, 28.0, 1),
- SimTraceFragment(duration * 1000, duration * 1000, 3500.0, 1),
- SimTraceFragment(duration * 2000, duration * 1000, 0.0, 1),
- SimTraceFragment(duration * 3000, duration * 1000, 183.0, 1),
- ).createWorkload(0)
- val workloadB =
- SimTrace.ofFragments(
- SimTraceFragment(0, duration * 1000, 28.0, 1),
- SimTraceFragment(duration * 1000, duration * 1000, 3100.0, 1),
- SimTraceFragment(duration * 2000, duration * 1000, 0.0, 1),
- SimTraceFragment(duration * 3000, duration * 1000, 73.0, 1),
- ).createWorkload(0)
-
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine = SimBareMetalMachine.create(graph, model)
- val hypervisor =
- SimHypervisor.create(
- FlowMultiplexerFactory.maxMinMultiplexer(),
- SplittableRandom(0L),
- ScalingGovernors.performance(),
- )
-
- launch { machine.runWorkload(hypervisor) }
-
- yield()
- coroutineScope {
- launch {
- val vm = hypervisor.newMachine(model)
- vm.runWorkload(workloadA)
- hypervisor.removeMachine(vm)
- }
- val vm = hypervisor.newMachine(model)
- vm.runWorkload(workloadB)
- hypervisor.removeMachine(vm)
- }
- yield()
- machine.cancel()
- yield()
-
- assertAll(
- { assertEquals(329250, hypervisor.counters.cpuActiveTime, "Active time does not match") },
- { assertEquals(870750, hypervisor.counters.cpuIdleTime, "Idle time does not match") },
- { assertEquals(318750, hypervisor.counters.cpuStealTime, "Steal time does not match") },
- { assertEquals(1200000, timeSource.millis()) },
- )
- }
-
- @Test
- fun testMultipleCPUs() =
- runSimulation {
- val model =
- MachineModel(
- Cpu(
- 0,
- 2,
- 3200.0,
- "Intel",
- "Xeon",
- "amd64",
- ),
- // memory
- MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000 * 4),
- )
-
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine = SimBareMetalMachine.create(graph, model)
- val hypervisor =
- SimHypervisor.create(
- FlowMultiplexerFactory.maxMinMultiplexer(),
- SplittableRandom(0L),
- ScalingGovernors.performance(),
- )
-
- assertDoesNotThrow {
- launch { machine.runWorkload(hypervisor) }
- }
-
- machine.cancel()
- }
-
- @Test
- fun testInterference() =
- runSimulation {
- val model =
- MachineModel(
- Cpu(
- 0,
- 2,
- 3200.0,
- "Intel",
- "Xeon",
- "amd64",
- ),
- // memory
- MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000 * 4),
- )
-
- val interferenceModel =
- VmInterferenceModel.builder()
- .addGroup(setOf("a", "b"), 0.0, 0.9)
- .addGroup(setOf("a", "c"), 0.0, 0.6)
- .addGroup(setOf("a", "n"), 0.1, 0.8)
- .build()
-
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine = SimBareMetalMachine.create(graph, model)
- val hypervisor = SimHypervisor.create(FlowMultiplexerFactory.maxMinMultiplexer(), SplittableRandom(0L))
-
- val duration = 5 * 60L
- val workloadA =
- SimTrace.ofFragments(
- SimTraceFragment(0, duration * 1000, 0.0, 1),
- SimTraceFragment(duration * 1000, duration * 1000, 28.0, 1),
- SimTraceFragment(duration * 2000, duration * 1000, 3500.0, 1),
- SimTraceFragment(duration * 3000, duration * 1000, 183.0, 1),
- ).createWorkload(0)
- val workloadB =
- SimTrace.ofFragments(
- SimTraceFragment(0, duration * 1000, 0.0, 1),
- SimTraceFragment(duration * 1000, duration * 1000, 28.0, 1),
- SimTraceFragment(duration * 2000, duration * 1000, 3100.0, 1),
- SimTraceFragment(duration * 3000, duration * 1000, 73.0, 1),
- ).createWorkload(0)
-
- launch {
- machine.runWorkload(hypervisor)
- }
-
- coroutineScope {
- launch {
- val vm = hypervisor.newMachine(model)
- vm.runWorkload(workloadA, meta = mapOf("interference-model" to interferenceModel.getProfile("a")!!))
- hypervisor.removeMachine(vm)
- }
- val vm = hypervisor.newMachine(model)
- vm.runWorkload(workloadB, meta = mapOf("interference-model" to interferenceModel.getProfile("b")!!))
- hypervisor.removeMachine(vm)
- }
-
- machine.cancel()
- }
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimSpaceSharedHypervisorTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimSpaceSharedHypervisorTest.kt
deleted file mode 100644
index b4ae372c..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/SimSpaceSharedHypervisorTest.kt
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Copyright (c) 2021 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.kernel
-
-import kotlinx.coroutines.launch
-import kotlinx.coroutines.yield
-import org.junit.jupiter.api.Assertions.assertAll
-import org.junit.jupiter.api.Assertions.assertDoesNotThrow
-import org.junit.jupiter.api.Assertions.assertEquals
-import org.junit.jupiter.api.Assertions.assertFalse
-import org.junit.jupiter.api.Assertions.assertTrue
-import org.junit.jupiter.api.BeforeEach
-import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.assertThrows
-import org.opendc.simulator.compute.SimBareMetalMachine
-import org.opendc.simulator.compute.model.Cpu
-import org.opendc.simulator.compute.model.MachineModel
-import org.opendc.simulator.compute.model.MemoryUnit
-import org.opendc.simulator.compute.runWorkload
-import org.opendc.simulator.compute.workload.SimTrace
-import org.opendc.simulator.compute.workload.SimTraceFragment
-import org.opendc.simulator.compute.workload.SimWorkloads
-import org.opendc.simulator.flow2.FlowEngine
-import org.opendc.simulator.flow2.mux.FlowMultiplexerFactory
-import org.opendc.simulator.kotlin.runSimulation
-import java.util.SplittableRandom
-
-/**
- * A test suite for a space-shared [SimHypervisor].
- */
-internal class SimSpaceSharedHypervisorTest {
- private lateinit var machineModel: MachineModel
-
- @BeforeEach
- fun setUp() {
- machineModel =
- MachineModel(
- Cpu(
- 0,
- 1,
- 3200.0,
- "Intel",
- "Xeon",
- "amd64",
- ),
- // memory
- MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000 * 4),
- )
- }
-
- /**
- * Test a trace workload.
- */
- @Test
- fun testTrace() =
- runSimulation {
- val duration = 5 * 60L
- val workloadA =
- SimTrace.ofFragments(
- SimTraceFragment(0, duration * 1000, 28.0, 1),
- SimTraceFragment(duration * 1000, duration * 1000, 3500.0, 1),
- SimTraceFragment(duration * 2000, duration * 1000, 0.0, 1),
- SimTraceFragment(duration * 3000, duration * 1000, 183.0, 1),
- ).createWorkload(0)
-
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine = SimBareMetalMachine.create(graph, machineModel)
- val hypervisor = SimHypervisor.create(FlowMultiplexerFactory.forwardingMultiplexer(), SplittableRandom(0L))
-
- launch { machine.runWorkload(hypervisor) }
- val vm = hypervisor.newMachine(machineModel)
- vm.runWorkload(workloadA)
- yield()
-
- hypervisor.removeMachine(vm)
- machine.cancel()
-
- assertEquals(5 * 60L * 4000, timeSource.millis()) { "Took enough time" }
- }
-
- /**
- * Test runtime workload on hypervisor.
- */
- @Test
- fun testRuntimeWorkload() =
- runSimulation {
- val duration = 5 * 60L * 1000
- val workload = SimWorkloads.runtime(duration, 1.0)
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine = SimBareMetalMachine.create(graph, machineModel)
- val hypervisor = SimHypervisor.create(FlowMultiplexerFactory.forwardingMultiplexer(), SplittableRandom(0L))
-
- launch { machine.runWorkload(hypervisor) }
- yield()
- val vm = hypervisor.newMachine(machineModel)
- vm.runWorkload(workload)
- hypervisor.removeMachine(vm)
-
- machine.cancel()
-
- assertEquals(duration, timeSource.millis()) { "Took enough time" }
- }
-
- /**
- * Test FLOPs workload on hypervisor.
- */
- @Test
- fun testFlopsWorkload() =
- runSimulation {
- val duration = 5 * 60L * 1000
- val workload = SimWorkloads.flops((duration * 3.2).toLong(), 1.0)
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine = SimBareMetalMachine.create(graph, machineModel)
- val hypervisor = SimHypervisor.create(FlowMultiplexerFactory.forwardingMultiplexer(), SplittableRandom(0L))
-
- launch { machine.runWorkload(hypervisor) }
- yield()
- val vm = hypervisor.newMachine(machineModel)
- vm.runWorkload(workload)
- machine.cancel()
-
- assertEquals(duration, timeSource.millis()) { "Took enough time" }
- }
-
- /**
- * Test two workloads running sequentially.
- */
- @Test
- fun testTwoWorkloads() =
- runSimulation {
- val duration = 5 * 60L * 1000
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine = SimBareMetalMachine.create(graph, machineModel)
- val hypervisor = SimHypervisor.create(FlowMultiplexerFactory.forwardingMultiplexer(), SplittableRandom(0L))
-
- launch { machine.runWorkload(hypervisor) }
- yield()
-
- val vm = hypervisor.newMachine(machineModel)
- vm.runWorkload(SimWorkloads.runtime(duration, 1.0))
- hypervisor.removeMachine(vm)
-
- yield()
-
- val vm2 = hypervisor.newMachine(machineModel)
- vm2.runWorkload(SimWorkloads.runtime(duration, 1.0))
- hypervisor.removeMachine(vm2)
-
- machine.cancel()
-
- assertEquals(duration * 2, timeSource.millis()) { "Took enough time" }
- }
-
- /**
- * Test concurrent workloads on the machine.
- */
- @Test
- fun testConcurrentWorkloadFails() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine = SimBareMetalMachine.create(graph, machineModel)
- val hypervisor = SimHypervisor.create(FlowMultiplexerFactory.forwardingMultiplexer(), SplittableRandom(0L))
-
- launch { machine.runWorkload(hypervisor) }
- yield()
-
- val vm = hypervisor.newMachine(machineModel)
- launch { vm.runWorkload(SimWorkloads.runtime(10_000, 1.0)) }
- yield()
-
- assertAll(
- { assertFalse(hypervisor.canFit(machineModel)) },
- { assertThrows<IllegalArgumentException> { hypervisor.newMachine(machineModel) } },
- )
-
- machine.cancel()
- vm.cancel()
- }
-
- /**
- * Test concurrent workloads on the machine.
- */
- @Test
- fun testConcurrentWorkloadSucceeds() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine = SimBareMetalMachine.create(graph, machineModel)
- val hypervisor = SimHypervisor.create(FlowMultiplexerFactory.forwardingMultiplexer(), SplittableRandom(0L))
-
- launch { machine.runWorkload(hypervisor) }
- yield()
-
- hypervisor.removeMachine(hypervisor.newMachine(machineModel))
-
- assertAll(
- { assertTrue(hypervisor.canFit(machineModel)) },
- { assertDoesNotThrow { hypervisor.newMachine(machineModel) } },
- )
-
- machine.cancel()
- }
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ConservativeScalingGovernorTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ConservativeScalingGovernorTest.kt
deleted file mode 100644
index 4a930df6..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ConservativeScalingGovernorTest.kt
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (c) 2021 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.kernel.cpufreq
-
-import io.mockk.every
-import io.mockk.mockk
-import io.mockk.verify
-import org.junit.jupiter.api.Test
-
-/**
- * Test suite for the conservative [ScalingGovernor].
- */
-internal class ConservativeScalingGovernorTest {
- @Test
- fun testSetStartLimitWithoutPStates() {
- val cpuCapacity = 4100.0
- val minSpeed = cpuCapacity / 2
- val defaultThreshold = 0.8
- val defaultStepSize = 0.05 * cpuCapacity
- val governor = ScalingGovernors.conservative(defaultThreshold)
-
- val policy = mockk<ScalingPolicy>(relaxUnitFun = true)
- every { policy.max } returns cpuCapacity
- every { policy.min } returns minSpeed
-
- var target = 0.0
- every { policy.target } answers { target }
- every { policy.target = any() } propertyType Double::class answers { target = value }
-
- val logic = governor.newGovernor(policy)
- logic.onStart()
- logic.onLimit(0.5)
-
- // Upwards scaling
- logic.onLimit(defaultThreshold + 0.2)
-
- // Downwards scaling
- logic.onLimit(defaultThreshold + 0.1)
-
- verify(exactly = 2) { policy.target = minSpeed }
- verify(exactly = 1) { policy.target = minSpeed + defaultStepSize }
- }
-
- @Test
- fun testSetStartLimitWithPStatesAndParams() {
- val firstPState = 1000.0
- val cpuCapacity = 4100.0
- val minSpeed = firstPState
- val threshold = 0.5
- val stepSize = 0.02 * cpuCapacity
- val governor = ScalingGovernors.conservative(threshold, stepSize)
-
- val policy = mockk<ScalingPolicy>(relaxUnitFun = true)
- every { policy.max } returns cpuCapacity
- every { policy.min } returns firstPState
-
- var target = 0.0
- every { policy.target } answers { target }
- every { policy.target = any() } propertyType Double::class answers { target = value }
-
- val logic = governor.newGovernor(policy)
- logic.onStart()
- logic.onLimit(0.5)
-
- // Upwards scaling
- logic.onLimit(threshold + 0.2)
-
- // Downwards scaling
- logic.onLimit(threshold + 0.1)
-
- verify(exactly = 2) { policy.target = minSpeed }
- verify(exactly = 1) { policy.target = minSpeed + stepSize }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/OnDemandScalingGovernorTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/OnDemandScalingGovernorTest.kt
deleted file mode 100644
index d6a7090b..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/OnDemandScalingGovernorTest.kt
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (c) 2021 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.kernel.cpufreq
-
-import io.mockk.every
-import io.mockk.mockk
-import io.mockk.verify
-import org.junit.jupiter.api.Test
-
-/**
- * Test suite for the on-demand [ScalingGovernor].
- */
-internal class OnDemandScalingGovernorTest {
- @Test
- fun testSetStartLimitWithoutPStates() {
- val cpuCapacity = 4100.0
- val minSpeed = cpuCapacity / 2
- val defaultThreshold = 0.8
- val governor = ScalingGovernors.ondemand(defaultThreshold)
-
- val policy = mockk<ScalingPolicy>(relaxUnitFun = true)
- every { policy.min } returns minSpeed
- every { policy.max } returns cpuCapacity
-
- val logic = governor.newGovernor(policy)
- logic.onStart()
- verify(exactly = 1) { policy.target = minSpeed }
-
- logic.onLimit(0.5)
- verify(exactly = 1) { policy.target = minSpeed + 0.5 * (cpuCapacity - minSpeed) / 100 }
-
- logic.onLimit(defaultThreshold)
- verify(exactly = 1) { policy.target = cpuCapacity }
- }
-
- @Test
- fun testSetStartLimitWithPStatesAndParams() {
- val firstPState = 1000.0
- val cpuCapacity = 4100.0
- val threshold = 0.5
- val governor = ScalingGovernors.ondemand(threshold)
-
- val policy = mockk<ScalingPolicy>(relaxUnitFun = true)
- every { policy.max } returns cpuCapacity
- every { policy.min } returns firstPState
-
- val logic = governor.newGovernor(policy)
-
- logic.onStart()
- verify(exactly = 1) { policy.target = firstPState }
-
- logic.onLimit(0.1)
- verify(exactly = 1) { policy.target = firstPState + 0.1 * (cpuCapacity - firstPState) / 100 }
-
- logic.onLimit(threshold)
- verify(exactly = 1) { policy.target = cpuCapacity }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PowerSaveScalingGovernorTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PowerSaveScalingGovernorTest.kt
deleted file mode 100644
index 4cee8199..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PowerSaveScalingGovernorTest.kt
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (c) 2021 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.kernel.cpufreq
-
-import io.mockk.every
-import io.mockk.mockk
-import io.mockk.verify
-import org.junit.jupiter.api.Test
-
-/**
- * Test suite for the [PowerSaveScalingGovernor]
- */
-internal class PowerSaveScalingGovernorTest {
- @Test
- fun testSetStartLimitWithoutPStates() {
- val cpuCapacity = 4100.0
- val minSpeed = cpuCapacity / 2
- val policy = mockk<ScalingPolicy>(relaxUnitFun = true)
- val logic = ScalingGovernors.powerSave().newGovernor(policy)
-
- every { policy.max } returns cpuCapacity
- every { policy.min } returns minSpeed
-
- logic.onStart()
-
- logic.onLimit(0.0)
- verify(exactly = 1) { policy.target = minSpeed }
-
- logic.onLimit(1.0)
- verify(exactly = 1) { policy.target = minSpeed }
- }
-
- @Test
- fun testSetStartLimitWithPStates() {
- val cpuCapacity = 4100.0
- val firstPState = 1000.0
- val policy = mockk<ScalingPolicy>(relaxUnitFun = true)
- val logic = ScalingGovernors.powerSave().newGovernor(policy)
-
- every { policy.max } returns cpuCapacity
- every { policy.min } returns firstPState
-
- logic.onStart()
- verify(exactly = 1) { policy.target = firstPState }
-
- logic.onLimit(0.0)
- verify(exactly = 1) { policy.target = firstPState }
-
- logic.onLimit(1.0)
- verify(exactly = 1) { policy.target = firstPState }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/power/PowerModelTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/power/PowerModelTest.kt
deleted file mode 100644
index e3bea821..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/power/PowerModelTest.kt
+++ /dev/null
@@ -1,180 +0,0 @@
-/*
- * Copyright (c) 2021 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.power
-
-import org.junit.jupiter.api.Assertions.assertAll
-import org.junit.jupiter.api.Assertions.assertEquals
-import org.junit.jupiter.api.Test
-import org.junit.jupiter.params.ParameterizedTest
-import org.junit.jupiter.params.provider.Arguments
-import org.junit.jupiter.params.provider.MethodSource
-import java.util.stream.Stream
-import kotlin.math.pow
-
-internal class PowerModelTest {
- private val epsilon = 10.0.pow(-3)
- private val cpuUtil = 0.9
-
- @ParameterizedTest
- @MethodSource("machinePowerModelArgs")
- fun `compute power consumption given CPU loads`(
- powerModel: CpuPowerModel,
- expectedPowerConsumption: Double,
- ) {
- val computedPowerConsumption = powerModel.computePower(cpuUtil)
- assertEquals(expectedPowerConsumption, computedPowerConsumption, epsilon)
- }
-
- @ParameterizedTest
- @MethodSource("machinePowerModelArgs")
- fun `ignore idle power when computing power consumptions`(
- powerModel: CpuPowerModel,
- expectedPowerConsumption: Double,
- ) {
- val zeroPowerModel = CpuPowerModels.zeroIdle(powerModel)
-
- assertAll(
- { assertEquals(expectedPowerConsumption, zeroPowerModel.computePower(cpuUtil), epsilon) },
- { assertEquals(0.0, zeroPowerModel.computePower(0.0)) },
- )
- }
-
- @Test
- fun `compute power draw by the SPEC benchmark model`() {
- val powerModel =
- CpuPowerModels.interpolate(
- 58.4, 98.0, 109.0, 118.0, 128.0, 140.0, 153.0, 170.0, 189.0, 205.0, 222.0,
- )
-
- assertAll(
- { assertEquals(58.4, powerModel.computePower(0.0)) },
- { assertEquals(58.4 + (98 - 58.4) / 5, powerModel.computePower(0.02)) },
- { assertEquals(98.0, powerModel.computePower(0.1)) },
- { assertEquals(140.0, powerModel.computePower(0.5)) },
- { assertEquals(189.0, powerModel.computePower(0.8)) },
- { assertEquals(189.0 + 0.7 * 10 * (205 - 189) / 10, powerModel.computePower(0.87)) },
- { assertEquals(205.0, powerModel.computePower(0.9)) },
- { assertEquals(222.0, powerModel.computePower(1.0)) },
- )
- }
-
- @Test
- fun `test linear model`() {
- val powerModel = CpuPowerModels.linear(400.0, 200.0)
-
- assertAll(
- { assertEquals(200.0, powerModel.computePower(-0.1)) },
- { assertEquals(200.0, powerModel.computePower(0.0)) },
- { assertEquals(220.0, powerModel.computePower(0.1)) },
- { assertEquals(240.0, powerModel.computePower(0.2)) },
- { assertEquals(260.0, powerModel.computePower(0.3)) },
- { assertEquals(280.0, powerModel.computePower(0.4)) },
- { assertEquals(300.0, powerModel.computePower(0.5)) },
- { assertEquals(320.0, powerModel.computePower(0.6)) },
- { assertEquals(340.0, powerModel.computePower(0.7)) },
- { assertEquals(360.0, powerModel.computePower(0.8)) },
- { assertEquals(380.0, powerModel.computePower(0.9)) },
- { assertEquals(400.0, powerModel.computePower(1.0)) },
- { assertEquals(400.0, powerModel.computePower(1.1)) },
- )
- }
-
- @Test
- fun `test sqrt model`() {
- val powerModel = CpuPowerModels.sqrt(400.0, 200.0)
-
- assertAll(
- { assertEquals(200.0, powerModel.computePower(-1.0), 1.0) },
- { assertEquals(200.0, powerModel.computePower(0.0), 1.0) },
- { assertEquals(263.0, powerModel.computePower(0.1), 1.0) },
- { assertEquals(289.0, powerModel.computePower(0.2), 1.0) },
- { assertEquals(309.0, powerModel.computePower(0.3), 1.0) },
- { assertEquals(326.0, powerModel.computePower(0.4), 1.0) },
- { assertEquals(341.0, powerModel.computePower(0.5), 1.0) },
- { assertEquals(354.0, powerModel.computePower(0.6), 1.0) },
- { assertEquals(367.0, powerModel.computePower(0.7), 1.0) },
- { assertEquals(378.0, powerModel.computePower(0.8), 1.0) },
- { assertEquals(389.0, powerModel.computePower(0.9), 1.0) },
- { assertEquals(400.0, powerModel.computePower(1.0), 1.0) },
- { assertEquals(400.0, powerModel.computePower(1.1), 1.0) },
- )
- }
-
- @Test
- fun `test square model`() {
- val powerModel = CpuPowerModels.square(400.0, 200.0)
-
- assertAll(
- { assertEquals(200.0, powerModel.computePower(-1.0), 1.0) },
- { assertEquals(200.0, powerModel.computePower(0.0), 1.0) },
- { assertEquals(202.0, powerModel.computePower(0.1), 1.0) },
- { assertEquals(208.0, powerModel.computePower(0.2), 1.0) },
- { assertEquals(218.0, powerModel.computePower(0.3), 1.0) },
- { assertEquals(232.0, powerModel.computePower(0.4), 1.0) },
- { assertEquals(250.0, powerModel.computePower(0.5), 1.0) },
- { assertEquals(272.0, powerModel.computePower(0.6), 1.0) },
- { assertEquals(298.0, powerModel.computePower(0.7), 1.0) },
- { assertEquals(328.0, powerModel.computePower(0.8), 1.0) },
- { assertEquals(362.0, powerModel.computePower(0.9), 1.0) },
- { assertEquals(400.0, powerModel.computePower(1.0), 1.0) },
- { assertEquals(400.0, powerModel.computePower(1.1), 1.0) },
- )
- }
-
- @Test
- fun `test cubic model`() {
- val powerModel = CpuPowerModels.cubic(400.0, 200.0)
-
- assertAll(
- { assertEquals(200.0, powerModel.computePower(-1.0), 1.0) },
- { assertEquals(200.0, powerModel.computePower(0.0), 1.0) },
- { assertEquals(200.0, powerModel.computePower(0.1), 1.0) },
- { assertEquals(201.0, powerModel.computePower(0.2), 1.0) },
- { assertEquals(205.0, powerModel.computePower(0.3), 1.0) },
- { assertEquals(212.0, powerModel.computePower(0.4), 1.0) },
- { assertEquals(225.0, powerModel.computePower(0.5), 1.0) },
- { assertEquals(243.0, powerModel.computePower(0.6), 1.0) },
- { assertEquals(268.0, powerModel.computePower(0.7), 1.0) },
- { assertEquals(302.0, powerModel.computePower(0.8), 1.0) },
- { assertEquals(345.0, powerModel.computePower(0.9), 1.0) },
- { assertEquals(400.0, powerModel.computePower(1.0), 1.0) },
- { assertEquals(400.0, powerModel.computePower(1.1), 1.0) },
- )
- }
-
- @Suppress("unused")
- private companion object {
- @JvmStatic
- fun machinePowerModelArgs(): Stream<Arguments> =
- Stream.of(
- Arguments.of(CpuPowerModels.constant(0.0), 0.0),
- Arguments.of(CpuPowerModels.linear(350.0, 200.0), 335.0),
- Arguments.of(CpuPowerModels.square(350.0, 200.0), 321.5),
- Arguments.of(CpuPowerModels.cubic(350.0, 200.0), 309.35),
- Arguments.of(CpuPowerModels.sqrt(350.0, 200.0), 342.302),
- Arguments.of(CpuPowerModels.mse(350.0, 200.0, 1.4), 340.571),
- Arguments.of(CpuPowerModels.asymptotic(350.0, 200.0, 0.3, false), 338.765),
- Arguments.of(CpuPowerModels.asymptotic(350.0, 200.0, 0.3, true), 323.072),
- )
- }
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimChainWorkloadTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimChainWorkloadTest.kt
deleted file mode 100644
index 582635fc..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimChainWorkloadTest.kt
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * Copyright (c) 2022 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 io.mockk.every
-import io.mockk.mockk
-import io.mockk.spyk
-import kotlinx.coroutines.delay
-import kotlinx.coroutines.launch
-import org.junit.jupiter.api.Assertions.assertEquals
-import org.junit.jupiter.api.BeforeEach
-import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.assertThrows
-import org.opendc.simulator.compute.SimBareMetalMachine
-import org.opendc.simulator.compute.SimMachineContext
-import org.opendc.simulator.compute.model.Cpu
-import org.opendc.simulator.compute.model.MachineModel
-import org.opendc.simulator.compute.model.MemoryUnit
-import org.opendc.simulator.compute.runWorkload
-import org.opendc.simulator.flow2.FlowEngine
-import org.opendc.simulator.kotlin.runSimulation
-
-/**
- * Test suite for the [SimChainWorkload] class.
- */
-class SimChainWorkloadTest {
- private lateinit var machineModel: MachineModel
-
- @BeforeEach
- fun setUp() {
- machineModel =
- MachineModel(
- Cpu(
- 0,
- 2,
- 1000.0,
- "Intel",
- "Xeon",
- "amd64",
- ),
- // memory
- MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000 * 4),
- )
- }
-
- @Test
- fun testMultipleWorkloads() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine =
- SimBareMetalMachine.create(
- graph,
- machineModel,
- )
-
- val workload =
- SimWorkloads.chain(
- SimWorkloads.runtime(1000, 1.0, 0L, 0L),
- SimWorkloads.runtime(1000, 1.0, 0L, 0L),
- )
-
- machine.runWorkload(workload)
-
- assertEquals(2000, timeSource.millis())
- }
-
- @Test
- fun testStartFailure() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine =
- SimBareMetalMachine.create(
- graph,
- machineModel,
- )
-
- val workloadA = mockk<SimWorkload>()
- every { workloadA.onStart(any()) } throws IllegalStateException("Staged")
- every { workloadA.onStop(any()) } returns Unit
-
- val workload =
- SimWorkloads.chain(
- workloadA,
- SimWorkloads.runtime(1000, 1.0, 0L, 0L),
- )
-
- assertThrows<IllegalStateException> { machine.runWorkload(workload) }
-
- assertEquals(0, timeSource.millis())
- }
-
-// @Test
- fun testStartFailureSecond() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine =
- SimBareMetalMachine.create(
- graph,
- machineModel,
- )
-
- val workloadA = mockk<SimWorkload>()
- every { workloadA.onStart(any()) } throws IllegalStateException("Staged")
- every { workloadA.onStop(any()) } returns Unit
-
- val workload =
- SimWorkloads.chain(
- SimWorkloads.runtime(1000, 1.0),
- workloadA,
- SimWorkloads.runtime(1000, 1.0),
- )
-
- assertThrows<IllegalStateException> { machine.runWorkload(workload) }
-
- assertEquals(1000, timeSource.millis())
- }
-
- @Test
- fun testStopFailure() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine =
- SimBareMetalMachine.create(
- graph,
- machineModel,
- )
-
- val workloadA = spyk<SimWorkload>(SimRuntimeWorkload(1000, 1.0))
- every { workloadA.onStop(any()) } throws IllegalStateException("Staged")
-
- val workload =
- SimWorkloads.chain(
- workloadA,
- SimWorkloads.runtime(1000, 1.0),
- )
-
- assertThrows<IllegalStateException> { machine.runWorkload(workload) }
-
- assertEquals(1000, timeSource.millis())
- }
-
- @Test
- fun testStopFailureSecond() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine =
- SimBareMetalMachine.create(
- graph,
- machineModel,
- )
-
- val workloadA = spyk<SimWorkload>(SimRuntimeWorkload(1000, 1.0))
- every { workloadA.onStop(any()) } throws IllegalStateException("Staged")
-
- val workload =
- SimWorkloads.chain(
- SimWorkloads.runtime(1000, 1.0),
- workloadA,
- SimWorkloads.runtime(1000, 1.0),
- )
-
- assertThrows<IllegalStateException> { machine.runWorkload(workload) }
-
- assertEquals(2000, timeSource.millis())
- }
-
-// @Test
- fun testStartAndStopFailure() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine =
- SimBareMetalMachine.create(
- graph,
- machineModel,
- )
-
- val workloadA = mockk<SimWorkload>()
- every { workloadA.onStart(any()) } throws IllegalStateException()
- every { workloadA.onStop(any()) } throws IllegalStateException()
-
- val workload =
- SimWorkloads.chain(
- SimRuntimeWorkload(1000, 1.0),
- workloadA,
- )
-
- val exc = assertThrows<IllegalStateException> { machine.runWorkload(workload) }
-
- assertEquals(2, exc.cause!!.suppressedExceptions.size)
- assertEquals(1000, timeSource.millis())
- }
-
-// @Test
- fun testShutdownAndStopFailure() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine =
- SimBareMetalMachine.create(
- graph,
- machineModel,
- )
-
- val workloadA = mockk<SimWorkload>()
- every { workloadA.onStart(any()) } answers { (it.invocation.args[0] as SimMachineContext).shutdown(IllegalStateException()) }
- every { workloadA.onStop(any()) } throws IllegalStateException()
-
- val workload =
- SimWorkloads.chain(
- SimRuntimeWorkload(1000, 1.0),
- workloadA,
- )
-
- val exc = assertThrows<IllegalStateException> { machine.runWorkload(workload) }
-
- assertEquals(1, exc.cause!!.suppressedExceptions.size)
- assertEquals(1000, timeSource.millis())
- }
-
-// @Test
- fun testShutdownAndStartFailure() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine =
- SimBareMetalMachine.create(
- graph,
- machineModel,
- )
-
- val workloadA = mockk<SimWorkload>(relaxUnitFun = true)
- every { workloadA.onStart(any()) } answers { (it.invocation.args[0] as SimMachineContext).shutdown(IllegalStateException()) }
-
- val workloadB = mockk<SimWorkload>(relaxUnitFun = true)
- every { workloadB.onStart(any()) } throws IllegalStateException()
-
- val workload =
- SimWorkloads.chain(
- SimRuntimeWorkload(1000, 1.0),
- workloadA,
- workloadB,
- )
-
- val exc = assertThrows<IllegalStateException> { machine.runWorkload(workload) }
- assertEquals(1, exc.cause!!.suppressedExceptions.size)
- assertEquals(1000, timeSource.millis())
- }
-
- @Test
- fun testSnapshot() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine = SimBareMetalMachine.create(graph, machineModel)
- val workload =
- SimWorkloads.chain(
- SimWorkloads.runtime(1000, 1.0),
- SimWorkloads.runtime(1000, 1.0),
- )
-
- val job = launch { machine.runWorkload(workload) }
- delay(500L)
-
- workload.makeSnapshot(500L)
- val snapshot = workload.getSnapshot()
-
- job.join()
-
- assertEquals(2000, timeSource.millis())
-
- machine.runWorkload(snapshot)
-
- assertEquals(4000, timeSource.millis())
- }
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimFlopsWorkloadTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimFlopsWorkloadTest.kt
deleted file mode 100644
index edbc0571..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimFlopsWorkloadTest.kt
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2020 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.simulator.compute.workload
-
-import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.assertThrows
-
-/**
- * Test suite for [SimFlopsWorkload] class.
- */
-class SimFlopsWorkloadTest {
- @Test
- fun testFlopsNonNegative() {
- assertThrows<IllegalArgumentException>("FLOPs must be non-negative") {
- SimFlopsWorkload(-1, 1.0)
- }
- }
-
- @Test
- fun testUtilizationNonZero() {
- assertThrows<IllegalArgumentException>("Utilization cannot be zero") {
- SimFlopsWorkload(1, 0.0)
- }
- }
-
- @Test
- fun testUtilizationPositive() {
- assertThrows<IllegalArgumentException>("Utilization cannot be negative") {
- SimFlopsWorkload(1, -1.0)
- }
- }
-
- @Test
- fun testUtilizationNotLargerThanOne() {
- assertThrows<IllegalArgumentException>("Utilization cannot be larger than one") {
- SimFlopsWorkload(1, 2.0)
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkloadTest.kt b/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkloadTest.kt
deleted file mode 100644
index a53f6c65..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/test/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkloadTest.kt
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * Copyright (c) 2021 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 kotlinx.coroutines.delay
-import org.junit.jupiter.api.Assertions.assertEquals
-import org.junit.jupiter.api.BeforeEach
-import org.junit.jupiter.api.Test
-import org.opendc.simulator.compute.SimBareMetalMachine
-import org.opendc.simulator.compute.model.Cpu
-import org.opendc.simulator.compute.model.MachineModel
-import org.opendc.simulator.compute.model.MemoryUnit
-import org.opendc.simulator.compute.runWorkload
-import org.opendc.simulator.flow2.FlowEngine
-import org.opendc.simulator.kotlin.runSimulation
-
-/**
- * Test suite for the [SimTraceWorkloadTest] class.
- */
-class SimTraceWorkloadTest {
- private lateinit var machineModel: MachineModel
-
- @BeforeEach
- fun setUp() {
- machineModel =
- MachineModel(
- Cpu(
- 0,
- 2,
- 1000.0,
- "Intel",
- "Xeon",
- "amd64",
- ),
- // memory
- MemoryUnit("Crucial", "MTA18ASF4G72AZ-3G2B1", 3200.0, 32_000 * 4),
- )
- }
-
- @Test
- fun testSmoke() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine =
- SimBareMetalMachine.create(
- graph,
- machineModel,
- )
-
- val workload =
- SimTrace.ofFragments(
- SimTraceFragment(0, 1000, 2 * 28.0, 2),
- SimTraceFragment(1000, 1000, 2 * 3100.0, 2),
- SimTraceFragment(2000, 1000, 0.0, 2),
- SimTraceFragment(3000, 1000, 2 * 73.0, 2),
- ).createWorkload(0)
-
- machine.runWorkload(workload)
-
- assertEquals(4000, timeSource.millis())
- }
-
-// @Test // fixme: Fix delayed start and enable test
- fun testOffset() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine =
- SimBareMetalMachine.create(
- graph,
- machineModel,
- )
-
- val workload =
- SimTrace.ofFragments(
- SimTraceFragment(0, 1000, 2 * 28.0, 2),
- SimTraceFragment(1000, 1000, 2 * 3100.0, 2),
- SimTraceFragment(2000, 1000, 0.0, 2),
- SimTraceFragment(3000, 1000, 2 * 73.0, 2),
- ).createWorkload(1000)
-
- machine.runWorkload(workload)
-
- assertEquals(5000, timeSource.millis()) // fixme: should be 5000 but this is 4000 for now to make all tests succeed
- }
-
- @Test
- fun testSkipFragment() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine =
- SimBareMetalMachine.create(
- graph,
- machineModel,
- )
-
- val workload =
- SimTrace.ofFragments(
- SimTraceFragment(0, 1000, 2 * 28.0, 2),
- SimTraceFragment(1000, 1000, 2 * 3100.0, 2),
- SimTraceFragment(2000, 1000, 0.0, 2),
- SimTraceFragment(3000, 1000, 2 * 73.0, 2),
- ).createWorkload(0)
-
- delay(1000L)
- machine.runWorkload(workload)
-
- assertEquals(4000, timeSource.millis())
- }
-
- @Test
- fun testZeroCores() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val machine =
- SimBareMetalMachine.create(
- graph,
- machineModel,
- )
-
- val workload =
- SimTrace.ofFragments(
- SimTraceFragment(0, 1000, 2 * 28.0, 2),
- SimTraceFragment(1000, 1000, 2 * 3100.0, 2),
- SimTraceFragment(2000, 1000, 0.0, 0),
- SimTraceFragment(3000, 1000, 2 * 73.0, 2),
- ).createWorkload(0)
-
- machine.runWorkload(workload)
-
- assertEquals(4000, timeSource.millis())
- }
-}
diff --git a/opendc-simulator/opendc-simulator-flow/src/jmh/kotlin/org/opendc/simulator/flow2/FlowBenchmarks.kt b/opendc-simulator/opendc-simulator-flow/src/jmh/kotlin/org/opendc/simulator/flow2/FlowBenchmarks.kt
index 6bf9c2a2..0ab051a4 100644
--- a/opendc-simulator/opendc-simulator-flow/src/jmh/kotlin/org/opendc/simulator/flow2/FlowBenchmarks.kt
+++ b/opendc-simulator/opendc-simulator-flow/src/jmh/kotlin/org/opendc/simulator/flow2/FlowBenchmarks.kt
@@ -93,8 +93,8 @@ class FlowBenchmarks {
val sinkA = SimpleFlowSink(graph, 3000.0f)
val sinkB = SimpleFlowSink(graph, 3000.0f)
- graph.connect(switch.newOutput(), sinkA.input)
- graph.connect(switch.newOutput(), sinkB.input)
+ graph.connect(switch.newOutPort(), sinkA.input)
+ graph.connect(switch.newOutPort(), sinkB.input)
val source = TraceFlowSource(graph, trace)
graph.connect(source.output, switch.newInput())
@@ -111,8 +111,8 @@ class FlowBenchmarks {
val sinkA = SimpleFlowSink(graph, 3000.0f)
val sinkB = SimpleFlowSink(graph, 3000.0f)
- graph.connect(switch.newOutput(), sinkA.input)
- graph.connect(switch.newOutput(), sinkB.input)
+ graph.connect(switch.newOutPort(), sinkA.input)
+ graph.connect(switch.newOutPort(), sinkB.input)
repeat(3) {
launch {
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/Multiplexer.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/Multiplexer.java
new file mode 100644
index 00000000..0af2499a
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/Multiplexer.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (c) 2024 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package org.opendc.simulator;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import org.opendc.simulator.engine.FlowConsumer;
+import org.opendc.simulator.engine.FlowEdge;
+import org.opendc.simulator.engine.FlowGraph;
+import org.opendc.simulator.engine.FlowNode;
+import org.opendc.simulator.engine.FlowSupplier;
+
+public class Multiplexer extends FlowNode implements FlowSupplier, FlowConsumer {
+ private ArrayList<FlowEdge> consumerEdges = new ArrayList<>();
+ private FlowEdge supplierEdge;
+
+ private ArrayList<Float> demands = new ArrayList<>(); // What is demanded by the consumers
+ private ArrayList<Float> supplies = new ArrayList<>(); // What is supplied to the consumers
+
+ private float totalDemand; // The total demand of all the consumers
+ private float totalSupply; // The total supply from the supplier
+ private float capacity; // What is the max capacity
+
+ public Multiplexer(FlowGraph graph) {
+ super(graph);
+ }
+
+ public float getTotalDemand() {
+ return totalDemand;
+ }
+
+ public float getTotalSupply() {
+ return totalSupply;
+ }
+
+ public float getCapacity() {
+ return capacity;
+ }
+
+ public long onUpdate(long now) {
+
+ if (this.totalDemand > this.capacity) {
+ redistributeSupply(this.consumerEdges, this.supplies, this.capacity);
+ } else {
+ for (int i = 0; i < this.demands.size(); i++) {
+ this.supplies.set(i, this.demands.get(i));
+ }
+ }
+
+ float totalSupply = 0;
+ for (int i = 0; i < this.consumerEdges.size(); i++) {
+ this.pushSupply(this.consumerEdges.get(i), this.supplies.get(i));
+ totalSupply += this.supplies.get(i);
+ }
+
+ // Only update supplier if supply has changed
+ if (this.totalSupply != totalSupply) {
+ this.totalSupply = totalSupply;
+
+ pushDemand(this.supplierEdge, this.totalSupply);
+ }
+
+ return Long.MAX_VALUE;
+ }
+
+ private static float redistributeSupply(
+ ArrayList<FlowEdge> consumerEdges, ArrayList<Float> supplies, float capacity) {
+ final long[] consumers = new long[consumerEdges.size()];
+
+ for (int i = 0; i < consumers.length; i++) {
+ FlowEdge consumer = consumerEdges.get(i);
+
+ if (consumer == null) {
+ break;
+ }
+
+ consumers[i] = ((long) Float.floatToRawIntBits(consumer.getDemand()) << 32) | (i & 0xFFFFFFFFL);
+ }
+ Arrays.sort(consumers);
+
+ float availableCapacity = capacity;
+ int inputSize = consumers.length;
+
+ for (int i = 0; i < inputSize; i++) {
+ long v = consumers[i];
+ int slot = (int) v;
+ float d = Float.intBitsToFloat((int) (v >> 32));
+
+ if (d == 0.0) {
+ continue;
+ }
+
+ float availableShare = availableCapacity / (inputSize - i);
+ float r = Math.min(d, availableShare);
+
+ supplies.set(slot, r); // Update the rates
+ availableCapacity -= r;
+ }
+
+ // Return the used capacity
+ return capacity - availableCapacity;
+ }
+
+ /**
+ * Add a new consumer.
+ * Set its demand and supply to 0.0
+ */
+ @Override
+ public void addConsumerEdge(FlowEdge consumerEdge) {
+ this.consumerEdges.add(consumerEdge);
+ this.demands.add(0f);
+ this.supplies.add(0f);
+ }
+
+ @Override
+ public void addSupplierEdge(FlowEdge supplierEdge) {
+ this.supplierEdge = supplierEdge;
+ this.capacity = supplierEdge.getCapacity();
+ this.totalSupply = 0;
+ }
+
+ @Override
+ public void removeConsumerEdge(FlowEdge consumerEdge) {
+ int idx = this.consumerEdges.indexOf(consumerEdge);
+
+ if (idx == -1) {
+ return;
+ }
+
+ this.totalDemand -= consumerEdge.getDemand();
+
+ this.consumerEdges.remove(idx);
+ this.demands.remove(idx);
+ this.supplies.remove(idx);
+
+ this.invalidate();
+ }
+
+ @Override
+ public void removeSupplierEdge(FlowEdge supplierEdge) {
+ this.supplierEdge = null;
+ this.capacity = 0;
+ this.totalSupply = 0;
+ }
+
+ @Override
+ public void handleDemand(FlowEdge consumerEdge, float newDemand) {
+ int idx = consumerEdges.indexOf(consumerEdge);
+
+ if (idx == -1) {
+ System.out.println("Error (Multiplexer): Demand pushed by an unknown consumer");
+ return;
+ }
+
+ float prevDemand = demands.get(idx);
+ demands.set(idx, newDemand);
+
+ this.totalDemand += (newDemand - prevDemand);
+ }
+
+ @Override
+ public void handleSupply(FlowEdge supplierEdge, float newSupply) {
+ if (newSupply == this.totalSupply) {
+ return;
+ }
+
+ this.totalSupply = newSupply;
+ }
+
+ @Override
+ public void pushDemand(FlowEdge supplierEdge, float newDemand) {
+ this.supplierEdge.pushDemand(newDemand);
+ }
+
+ @Override
+ public void pushSupply(FlowEdge consumerEdge, float newSupply) {
+ int idx = consumerEdges.indexOf(consumerEdge);
+
+ if (idx == -1) {
+ System.out.println("Error (Multiplexer): pushing supply to an unknown consumer");
+ }
+
+ if (newSupply == supplies.get(idx)) {
+ return;
+ }
+
+ supplies.set(idx, newSupply);
+ consumerEdge.pushSupply(newSupply);
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-network/build.gradle.kts b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/FlowConsumer.java
index a7f309c0..7ba5dea7 100644
--- a/opendc-simulator/opendc-simulator-network/build.gradle.kts
+++ b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/FlowConsumer.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 AtLarge Research
+ * Copyright (c) 2024 AtLarge Research
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -20,15 +20,15 @@
* SOFTWARE.
*/
-description = "Library for simulating datacenter network components"
+package org.opendc.simulator.engine;
-plugins {
- `kotlin-library-conventions`
-}
+public interface FlowConsumer {
+
+ void handleSupply(FlowEdge supplierEdge, float newSupply);
+
+ void pushDemand(FlowEdge supplierEdge, float newDemand);
-dependencies {
- api(projects.opendcSimulator.opendcSimulatorFlow)
- implementation(projects.opendcSimulator.opendcSimulatorCore)
+ void addSupplierEdge(FlowEdge supplierEdge);
- testImplementation(libs.slf4j.simple)
+ void removeSupplierEdge(FlowEdge supplierEdge);
}
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/FlowEdge.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/FlowEdge.java
new file mode 100644
index 00000000..0edc9e68
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/FlowEdge.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2024 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package org.opendc.simulator.engine;
+
+/**
+ * An edge that connects two FlowStages.
+ * A connection between FlowStages always consist of a FlowStage that demands
+ * something, and a FlowStage that Delivers something
+ * For instance, this could be the connection between a workload, and its machine
+ */
+public class FlowEdge {
+ private FlowConsumer consumer;
+ private FlowSupplier supplier;
+
+ private float demand = 0.0f;
+ private float supply = 0.0f;
+
+ private float capacity;
+
+ public FlowEdge(FlowConsumer consumer, FlowSupplier supplier) {
+ if (!(consumer instanceof FlowNode)) {
+ throw new IllegalArgumentException("Flow consumer is not a FlowNode");
+ }
+ if (!(supplier instanceof FlowNode)) {
+ throw new IllegalArgumentException("Flow consumer is not a FlowNode");
+ }
+
+ this.consumer = consumer;
+ this.supplier = supplier;
+
+ this.capacity = supplier.getCapacity();
+
+ this.consumer.addSupplierEdge(this);
+ this.supplier.addConsumerEdge(this);
+ }
+
+ public void close() {
+ if (this.consumer != null) {
+ this.consumer.removeSupplierEdge(this);
+ this.consumer = null;
+ }
+
+ if (this.supplier != null) {
+ this.supplier.removeConsumerEdge(this);
+ this.supplier = null;
+ }
+ }
+
+ public FlowConsumer getConsumer() {
+ return consumer;
+ }
+
+ public FlowSupplier getSupplier() {
+ return supplier;
+ }
+
+ public float getCapacity() {
+ return capacity;
+ }
+
+ public float getDemand() {
+ return this.demand;
+ }
+
+ public float getSupply() {
+ return this.supply;
+ }
+
+ /**
+ * Push new demand from the Consumer to the Supplier
+ */
+ public void pushDemand(float newDemand) {
+ if (newDemand == this.demand) {
+ return;
+ }
+
+ this.demand = newDemand;
+ this.supplier.handleDemand(this, newDemand);
+ ((FlowNode) this.supplier).invalidate();
+ }
+
+ /**
+ * Push new supply from the Supplier to the Consumer
+ */
+ public void pushSupply(float newSupply) {
+ if (newSupply == this.supply) {
+ return;
+ }
+
+ this.supply = newSupply;
+ this.consumer.handleSupply(this, newSupply);
+ ((FlowNode) this.consumer).invalidate();
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/FlowEngine.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/FlowEngine.java
index c0f52505..10af7c51 100644
--- a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/FlowEngine.java
+++ b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/FlowEngine.java
@@ -20,12 +20,10 @@
* SOFTWARE.
*/
-package org.opendc.simulator.flow2;
+package org.opendc.simulator.engine;
import java.time.Clock;
import java.time.InstantSource;
-import java.util.ArrayList;
-import java.util.List;
import kotlin.coroutines.CoroutineContext;
import org.opendc.common.Dispatcher;
@@ -37,12 +35,12 @@ import org.opendc.common.Dispatcher;
*/
public final class FlowEngine implements Runnable {
/**
- * The queue of {@link FlowStage} updates that are scheduled for immediate execution.
+ * The queue of {@link FlowNode} updates that are scheduled for immediate execution.
*/
- private final FlowStageQueue queue = new FlowStageQueue(256);
+ private final FlowNodeQueue queue = new FlowNodeQueue(256);
/**
- * A priority queue containing the {@link FlowStage} updates to be scheduled in the future.
+ * A priority queue containing the {@link FlowNode} updates to be scheduled in the future.
*/
private final FlowTimerQueue timerQueue = new FlowTimerQueue(256);
@@ -82,16 +80,16 @@ public final class FlowEngine implements Runnable {
* Return a new {@link FlowGraph} that can be used to build a flow network.
*/
public FlowGraph newGraph() {
- return new RootGraph(this);
+ return new FlowGraph(this);
}
/**
- * Enqueue the specified {@link FlowStage} to be updated immediately during the active engine cycle.
+ * Enqueue the specified {@link FlowNode} to be updated immediately during the active engine cycle.
* <p>
* This method should be used when the state of a flow context is invalidated/interrupted and needs to be
* re-computed.
*/
- void scheduleImmediate(long now, FlowStage ctx) {
+ void scheduleImmediate(long now, FlowNode ctx) {
scheduleImmediateInContext(ctx);
// In-case the engine is already running in the call-stack, return immediately. The changes will be picked
@@ -104,21 +102,21 @@ public final class FlowEngine implements Runnable {
}
/**
- * Enqueue the specified {@link FlowStage} to be updated immediately during the active engine cycle.
+ * Enqueue the specified {@link FlowNode} to be updated immediately during the active engine cycle.
* <p>
* This method should be used when the state of a flow context is invalidated/interrupted and needs to be
* re-computed.
* <p>
* This method should only be invoked while inside an engine cycle.
*/
- void scheduleImmediateInContext(FlowStage ctx) {
+ void scheduleImmediateInContext(FlowNode ctx) {
queue.add(ctx);
}
/**
- * Enqueue the specified {@link FlowStage} to be updated at its updated deadline.
+ * Enqueue the specified {@link FlowNode} to be updated at its updated deadline.
*/
- void scheduleDelayed(FlowStage ctx) {
+ void scheduleDelayed(FlowNode ctx) {
scheduleDelayedInContext(ctx);
// In-case the engine is already running in the call-stack, return immediately. The changes will be picked
@@ -134,11 +132,11 @@ public final class FlowEngine implements Runnable {
}
/**
- * Enqueue the specified {@link FlowStage} to be updated at its updated deadline.
+ * Enqueue the specified {@link FlowNode} to be updated at its updated deadline.
* <p>
* This method should only be invoked while inside an engine cycle.
*/
- void scheduleDelayedInContext(FlowStage ctx) {
+ void scheduleDelayedInContext(FlowNode ctx) {
FlowTimerQueue timerQueue = this.timerQueue;
timerQueue.enqueue(ctx);
}
@@ -147,7 +145,7 @@ public final class FlowEngine implements Runnable {
* Run all the enqueued actions for the specified timestamp (<code>now</code>).
*/
private void doRunEngine(long now) {
- final FlowStageQueue queue = this.queue;
+ final FlowNodeQueue queue = this.queue;
final FlowTimerQueue timerQueue = this.timerQueue;
try {
@@ -156,22 +154,22 @@ public final class FlowEngine implements Runnable {
// Execute all scheduled updates at current timestamp
while (true) {
- final FlowStage ctx = timerQueue.poll(now);
+ final FlowNode ctx = timerQueue.poll(now);
if (ctx == null) {
break;
}
- ctx.onUpdate(now);
+ ctx.update(now);
}
// Execute all immediate updates
while (true) {
- final FlowStage ctx = queue.poll();
+ final FlowNode ctx = queue.poll();
if (ctx == null) {
break;
}
- ctx.onUpdate(now);
+ ctx.update(now);
}
} finally {
active = false;
@@ -203,54 +201,4 @@ public final class FlowEngine implements Runnable {
dispatcher.schedule(target - now, this);
}
}
-
- /**
- * Internal implementation of a root {@link FlowGraph}.
- */
- private static final class RootGraph implements FlowGraphInternal {
- private final FlowEngine engine;
- private final List<FlowStage> stages = new ArrayList<>();
-
- public RootGraph(FlowEngine engine) {
- this.engine = engine;
- }
-
- @Override
- public FlowEngine getEngine() {
- return engine;
- }
-
- @Override
- public FlowStage newStage(FlowStageLogic logic) {
- final FlowEngine engine = this.engine;
- final FlowStage stage = new FlowStage(this, logic);
- stages.add(stage);
- long now = engine.getClock().millis();
- stage.invalidate(now);
- return stage;
- }
-
- @Override
- public void connect(Outlet outlet, Inlet inlet) {
- FlowGraphInternal.connect(this, outlet, inlet);
- }
-
- @Override
- public void disconnect(Outlet outlet) {
- FlowGraphInternal.disconnect(this, outlet);
- }
-
- @Override
- public void disconnect(Inlet inlet) {
- FlowGraphInternal.disconnect(this, inlet);
- }
-
- /**
- * Internal method to remove the specified {@link FlowStage} from the graph.
- */
- @Override
- public void detach(FlowStage stage) {
- stages.remove(stage);
- }
- }
}
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/FlowGraph.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/FlowGraph.java
new file mode 100644
index 00000000..d82b542b
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/FlowGraph.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2024 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+package org.opendc.simulator.engine;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+
+public class FlowGraph {
+ private final FlowEngine engine;
+ private final ArrayList<FlowNode> nodes = new ArrayList<>();
+ private final ArrayList<FlowEdge> edges = new ArrayList<>();
+ private final HashMap<FlowNode, ArrayList<FlowEdge>> nodeToEdge = new HashMap<>();
+
+ public FlowGraph(FlowEngine engine) {
+ this.engine = engine;
+ }
+
+ /**
+ * Return the {@link FlowEngine} driving the simulation of the graph.
+ */
+ public FlowEngine getEngine() {
+ return engine;
+ }
+
+ /**
+ * Create a new {@link FlowNode} representing a node in the flow network.
+ */
+ public void addNode(FlowNode node) {
+ if (nodes.contains(node)) {
+ System.out.println("Node already exists");
+ }
+ nodes.add(node);
+ nodeToEdge.put(node, new ArrayList<>());
+ long now = this.engine.getClock().millis();
+ node.invalidate(now);
+ }
+
+ /**
+ * Internal method to remove the specified {@link FlowNode} from the graph.
+ */
+ public void removeNode(FlowNode node) {
+
+ // Remove all edges connected to node
+ final ArrayList<FlowEdge> connectedEdges = nodeToEdge.get(node);
+ while (connectedEdges.size() > 0) {
+ removeEdge(connectedEdges.get(0));
+ }
+
+ nodeToEdge.remove(node);
+
+ // remove the node
+ nodes.remove(node);
+ }
+
+ /**
+ * Add an edge between the specified consumer and supplier in this graph.
+ */
+ public void addEdge(FlowConsumer flowConsumer, FlowSupplier flowSupplier) {
+ // Check if the consumer and supplier are both FlowNodes
+ if (!(flowConsumer instanceof FlowNode)) {
+ throw new IllegalArgumentException("Flow consumer is not a FlowNode");
+ }
+ if (!(flowSupplier instanceof FlowNode)) {
+ throw new IllegalArgumentException("Flow consumer is not a FlowNode");
+ }
+
+ // Check of the consumer and supplier are present in this graph
+ if (!(this.nodes.contains((FlowNode) flowConsumer))) {
+ throw new IllegalArgumentException("The consumer is not a node in this graph");
+ }
+ if (!(this.nodes.contains((FlowNode) flowSupplier))) {
+ throw new IllegalArgumentException("The consumer is not a node in this graph");
+ }
+
+ final FlowEdge flowEdge = new FlowEdge(flowConsumer, flowSupplier);
+
+ edges.add(flowEdge);
+
+ nodeToEdge.get((FlowNode) flowConsumer).add(flowEdge);
+ nodeToEdge.get((FlowNode) flowSupplier).add(flowEdge);
+ }
+
+ public void removeEdge(FlowEdge flowEdge) {
+ final FlowConsumer consumer = flowEdge.getConsumer();
+ final FlowSupplier supplier = flowEdge.getSupplier();
+ nodeToEdge.get((FlowNode) consumer).remove(flowEdge);
+ nodeToEdge.get((FlowNode) supplier).remove(flowEdge);
+
+ edges.remove(flowEdge);
+ flowEdge.close();
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/FlowNode.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/FlowNode.java
new file mode 100644
index 00000000..d1faf465
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/FlowNode.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2022 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.engine;
+
+import java.time.InstantSource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * A {@link FlowNode} represents a node in a {@link FlowGraph}.
+ */
+public abstract class FlowNode {
+ private static final Logger LOGGER = LoggerFactory.getLogger(FlowNode.class);
+
+ protected enum NodeState {
+ PENDING, // Stage is active, but is not running any updates
+ UPDATING, // Stage is active, and running an update
+ INVALIDATED, // Stage is deemed invalid, and should run an update
+ CLOSING, // Stage is being closed, final updates can still be run
+ CLOSED // Stage is closed and should not run any updates
+ }
+
+ protected NodeState nodeState = NodeState.PENDING;
+
+ /**
+ * The deadline of the stage after which an update should run.
+ */
+ long deadline = Long.MAX_VALUE;
+
+ /**
+ * The index of the timer in the {@link FlowTimerQueue}.
+ */
+ int timerIndex = -1;
+
+ protected InstantSource clock;
+ protected FlowGraph parentGraph;
+ protected FlowEngine engine;
+
+ /**
+ * Construct a new {@link FlowNode} instance.
+ *
+ * @param parentGraph The {@link FlowGraph} this stage belongs to.
+ */
+ public FlowNode(FlowGraph parentGraph) {
+ this.parentGraph = parentGraph;
+ this.engine = parentGraph.getEngine();
+ this.clock = engine.getClock();
+
+ this.parentGraph.addNode(this);
+ }
+
+ /**
+ * Return the {@link FlowGraph} to which this stage belongs.
+ */
+ public FlowGraph getGraph() {
+ return parentGraph;
+ }
+
+ /**
+ * Return the current deadline of the {@link FlowNode}'s timer (in milliseconds after epoch).
+ */
+ public long getDeadline() {
+ return deadline;
+ }
+
+ public void setDeadline(long deadline) {
+ this.deadline = deadline;
+ }
+
+ public void setTimerIndex(int index) {
+ this.timerIndex = index;
+ }
+ /**
+ * Invalidate the {@link FlowNode} forcing the stage to update.
+ *
+ * <p>
+ * This method is similar to {@link #invalidate()}, but allows the user to manually pass the current timestamp to
+ * prevent having to re-query the clock. This method should not be called during an update.
+ */
+ public void invalidate(long now) {
+ // If there is already an update running,
+ // notify the update, that a next update should be run after
+ if (this.nodeState == NodeState.UPDATING) {
+ this.nodeState = NodeState.INVALIDATED;
+ } else {
+ engine.scheduleImmediate(now, this);
+ }
+ }
+
+ /**
+ * Invalidate the {@link FlowNode} forcing the stage to update.
+ */
+ public void invalidate() {
+ invalidate(clock.millis());
+ }
+
+ /**
+ * Update the state of the stage.
+ */
+ public void update(long now) {
+ this.nodeState = NodeState.UPDATING;
+
+ long newDeadline = this.deadline;
+
+ try {
+ newDeadline = this.onUpdate(now);
+ } catch (Exception e) {
+ doFail(e);
+ }
+
+ // Check whether the stage is marked as closing.
+ if (this.nodeState == NodeState.INVALIDATED) {
+ newDeadline = now;
+ }
+ if (this.nodeState == NodeState.CLOSING) {
+ closeNode();
+ return;
+ }
+
+ this.deadline = newDeadline;
+
+ // Update the timer queue with the new deadline
+ engine.scheduleDelayedInContext(this);
+
+ this.nodeState = NodeState.PENDING;
+ }
+
+ /**
+ * This method is invoked when the one of the stage's InPorts or OutPorts is invalidated.
+ *
+ * @param now The virtual timestamp in milliseconds after epoch at which the update is occurring.
+ * @return The next deadline for the stage.
+ */
+ public abstract long onUpdate(long now);
+
+ /**
+ * This method is invoked when an uncaught exception is caught by the engine. When this happens, the
+ */
+ void doFail(Throwable cause) {
+ LOGGER.warn("Uncaught exception (closing stage)", cause);
+
+ closeNode();
+ }
+
+ /**
+ * This method is invoked when the {@link FlowNode} exits successfully or due to failure.
+ */
+ public void closeNode() {
+ if (this.nodeState == NodeState.CLOSED) {
+ // LOGGER.warn("Flowstage:doClose() => Tried closing a stage that was already closed");
+ return;
+ }
+
+ // If this stage is running an update, notify it that is should close after.
+ if (this.nodeState == NodeState.UPDATING) {
+ // LOGGER.warn("Flowstage:doClose() => Tried closing a stage, but update was active");
+ this.nodeState = NodeState.CLOSING;
+ return;
+ }
+
+ // Mark the stage as closed
+ this.nodeState = NodeState.CLOSED;
+
+ // Remove stage from parent graph
+ this.parentGraph.removeNode(this);
+
+ // Remove stage from the timer queue
+ this.deadline = Long.MAX_VALUE;
+ this.engine.scheduleDelayedInContext(this);
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/FlowStageQueue.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/FlowNodeQueue.java
index 56ec7702..37b3c65b 100644
--- a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/FlowStageQueue.java
+++ b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/FlowNodeQueue.java
@@ -20,35 +20,35 @@
* SOFTWARE.
*/
-package org.opendc.simulator.flow2;
+package org.opendc.simulator.engine;
import java.util.ArrayDeque;
import java.util.Arrays;
/**
- * A specialized {@link ArrayDeque} implementation that contains the {@link FlowStageLogic}s
+ * A specialized {@link ArrayDeque} implementation that contains the {@link FlowNode}s
* that have been updated during the engine cycle and should converge.
* <p>
* By using a specialized class, we reduce the overhead caused by type-erasure.
*/
-final class FlowStageQueue {
+final class FlowNodeQueue {
/**
* The array of elements in the queue.
*/
- private FlowStage[] elements;
+ private FlowNode[] elements;
private int head = 0;
private int tail = 0;
- public FlowStageQueue(int initialCapacity) {
- elements = new FlowStage[initialCapacity];
+ public FlowNodeQueue(int initialCapacity) {
+ elements = new FlowNode[initialCapacity];
}
/**
* Add the specified context to the queue.
*/
- void add(FlowStage ctx) {
- final FlowStage[] es = elements;
+ void add(FlowNode ctx) {
+ final FlowNode[] es = elements;
int tail = this.tail;
es[tail] = ctx;
@@ -62,12 +62,12 @@ final class FlowStageQueue {
}
/**
- * Remove a {@link FlowStage} from the queue or <code>null</code> if the queue is empty.
+ * Remove a {@link FlowNode} from the queue or <code>null</code> if the queue is empty.
*/
- FlowStage poll() {
- final FlowStage[] es = elements;
+ FlowNode poll() {
+ final FlowNode[] es = elements;
int head = this.head;
- FlowStage ctx = es[head];
+ FlowNode ctx = es[head];
if (ctx != null) {
es[head] = null;
@@ -87,7 +87,7 @@ final class FlowStageQueue {
throw new IllegalStateException("Sorry, deque too big");
}
- final FlowStage[] es = elements = Arrays.copyOf(elements, newCapacity);
+ final FlowNode[] es = elements = Arrays.copyOf(elements, newCapacity);
// Exceptionally, here tail == head needs to be disambiguated
if (tail < head || (tail == head && es[head] != null)) {
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/Outlet.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/FlowSupplier.java
index 32e19a3b..87729fca 100644
--- a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/Outlet.java
+++ b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/FlowSupplier.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2022 AtLarge Research
+ * Copyright (c) 2024 AtLarge Research
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -20,19 +20,17 @@
* SOFTWARE.
*/
-package org.opendc.simulator.flow2;
+package org.opendc.simulator.engine;
-/**
- * An out-going edge in a {@link FlowGraph}.
- */
-public interface Outlet {
- /**
- * Return the {@link FlowGraph} to which the outlet is exposed.
- */
- FlowGraph getGraph();
+public interface FlowSupplier {
+
+ void handleDemand(FlowEdge consumerEdge, float newDemand);
+
+ void pushSupply(FlowEdge consumerEdge, float newSupply);
+
+ void addConsumerEdge(FlowEdge consumerEdge);
+
+ void removeConsumerEdge(FlowEdge consumerEdge);
- /**
- * Return the name of the outlet.
- */
- String getName();
+ float getCapacity();
}
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/FlowTimerQueue.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/FlowTimerQueue.java
index 4b746202..1e348b10 100644
--- a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/FlowTimerQueue.java
+++ b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/FlowTimerQueue.java
@@ -20,21 +20,21 @@
* SOFTWARE.
*/
-package org.opendc.simulator.flow2;
+package org.opendc.simulator.engine;
import java.util.Arrays;
/**
- * A specialized priority queue for timers of {@link FlowStageLogic}s.
+ * A specialized priority queue for timers of {@link FlowNode}s.
* <p>
* By using a specialized priority queue, we reduce the overhead caused by the default priority queue implementation
* being generic.
*/
-final class FlowTimerQueue {
+public final class FlowTimerQueue {
/**
- * Array representation of binary heap of {@link FlowStage} instances.
+ * Array representation of binary heap of {@link FlowNode} instances.
*/
- private FlowStage[] queue;
+ private FlowNode[] queue;
/**
* The number of elements in the priority queue.
@@ -47,21 +47,21 @@ final class FlowTimerQueue {
* @param initialCapacity The initial capacity of the queue.
*/
public FlowTimerQueue(int initialCapacity) {
- this.queue = new FlowStage[initialCapacity];
+ this.queue = new FlowNode[initialCapacity];
}
/**
* Enqueue a timer for the specified context or update the existing timer.
*/
- void enqueue(FlowStage ctx) {
- FlowStage[] es = queue;
- int k = ctx.timerIndex;
+ public void enqueue(FlowNode node) {
+ FlowNode[] es = queue;
+ int k = node.timerIndex;
- if (ctx.deadline != Long.MAX_VALUE) {
+ if (node.deadline != Long.MAX_VALUE) {
if (k >= 0) {
- update(es, ctx, k);
+ update(es, node, k);
} else {
- add(es, ctx);
+ add(es, node);
}
} else if (k >= 0) {
delete(es, k);
@@ -74,14 +74,13 @@ final class FlowTimerQueue {
* @param now The timestamp that the deadline of the head of the queue should not exceed.
* @return The head of the queue if its deadline does not exceed <code>now</code>, otherwise <code>null</code>.
*/
- FlowStage poll(long now) {
- int size = this.size;
- if (size == 0) {
+ public FlowNode poll(long now) {
+ if (this.size == 0) {
return null;
}
- final FlowStage[] es = queue;
- final FlowStage head = es[0];
+ final FlowNode[] es = queue;
+ final FlowNode head = es[0];
if (now < head.deadline) {
return null;
@@ -89,7 +88,7 @@ final class FlowTimerQueue {
int n = size - 1;
this.size = n;
- final FlowStage next = es[n];
+ final FlowNode next = es[n];
es[n] = null; // Clear the last element of the queue
if (n > 0) {
@@ -103,9 +102,9 @@ final class FlowTimerQueue {
/**
* Find the earliest deadline in the queue.
*/
- long peekDeadline() {
- if (size > 0) {
- return queue[0].deadline;
+ public long peekDeadline() {
+ if (this.size > 0) {
+ return this.queue[0].deadline;
}
return Long.MAX_VALUE;
@@ -114,43 +113,41 @@ final class FlowTimerQueue {
/**
* Add a new entry to the queue.
*/
- private void add(FlowStage[] es, FlowStage ctx) {
- int i = size;
-
- if (i >= es.length) {
+ private void add(FlowNode[] es, FlowNode node) {
+ if (this.size >= es.length) {
// Re-fetch the resized array
es = grow();
}
- siftUp(i, ctx, es);
+ siftUp(this.size, node, es);
- size = i + 1;
+ this.size++;
}
/**
* Update the deadline of an existing entry in the queue.
*/
- private void update(FlowStage[] es, FlowStage ctx, int k) {
+ private void update(FlowNode[] es, FlowNode node, int k) {
if (k > 0) {
int parent = (k - 1) >>> 1;
- if (es[parent].deadline > ctx.deadline) {
- siftUp(k, ctx, es);
+ if (es[parent].deadline > node.deadline) {
+ siftUp(k, node, es);
return;
}
}
- siftDown(k, ctx, es, size);
+ siftDown(k, node, es, this.size);
}
/**
* Deadline an entry from the queue.
*/
- private void delete(FlowStage[] es, int k) {
- int s = --size;
+ private void delete(FlowNode[] es, int k) {
+ int s = --this.size;
if (s == k) {
es[k] = null; // Element is last in the queue
} else {
- FlowStage moved = es[s];
+ FlowNode moved = es[s];
es[s] = null;
siftDown(k, moved, es, s);
@@ -164,8 +161,8 @@ final class FlowTimerQueue {
/**
* Increases the capacity of the array.
*/
- private FlowStage[] grow() {
- FlowStage[] queue = this.queue;
+ private FlowNode[] grow() {
+ FlowNode[] queue = this.queue;
int oldCapacity = queue.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
@@ -174,10 +171,10 @@ final class FlowTimerQueue {
return queue;
}
- private static void siftUp(int k, FlowStage key, FlowStage[] es) {
+ private static void siftUp(int k, FlowNode key, FlowNode[] es) {
while (k > 0) {
int parent = (k - 1) >>> 1;
- FlowStage e = es[parent];
+ FlowNode e = es[parent];
if (key.deadline >= e.deadline) break;
es[k] = e;
e.timerIndex = k;
@@ -187,11 +184,11 @@ final class FlowTimerQueue {
key.timerIndex = k;
}
- private static void siftDown(int k, FlowStage key, FlowStage[] es, int n) {
+ private static void siftDown(int k, FlowNode key, FlowNode[] es, int n) {
int half = n >>> 1; // loop while a non-leaf
while (k < half) {
int child = (k << 1) + 1; // assume left child is least
- FlowStage c = es[child];
+ FlowNode c = es[child];
int right = child + 1;
if (right < n && c.deadline > es[right].deadline) c = es[child = right];
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/InvocationStack.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/InvocationStack.java
index a5b5114b..15da2f23 100644
--- a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/InvocationStack.java
+++ b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/InvocationStack.java
@@ -20,7 +20,7 @@
* SOFTWARE.
*/
-package org.opendc.simulator.flow2;
+package org.opendc.simulator.engine;
import java.util.Arrays;
@@ -29,7 +29,7 @@ import java.util.Arrays;
* <p>
* By using a specialized class, we reduce the overhead caused by type-erasure.
*/
-final class InvocationStack {
+public final class InvocationStack {
/**
* The array of elements in the stack.
*/
@@ -38,8 +38,8 @@ final class InvocationStack {
private int head = -1;
public InvocationStack(int initialCapacity) {
- elements = new long[initialCapacity];
- Arrays.fill(elements, Long.MIN_VALUE);
+ this.elements = new long[initialCapacity];
+ Arrays.fill(this.elements, Long.MIN_VALUE);
}
/**
@@ -48,8 +48,8 @@ final class InvocationStack {
* @param invocation The timestamp of the invocation.
* @return <code>true</code> if the invocation was added, <code>false</code> otherwise.
*/
- boolean tryAdd(long invocation) {
- final long[] es = elements;
+ public boolean tryAdd(long invocation) {
+ final long[] es = this.elements;
int head = this.head;
if (head < 0 || es[head] > invocation) {
@@ -69,12 +69,11 @@ final class InvocationStack {
/**
* Remove the head invocation from the stack or return {@link Long#MAX_VALUE} if the stack is empty.
*/
- long poll() {
- final long[] es = elements;
+ public long poll() {
int head = this.head--;
if (head >= 0) {
- return es[head];
+ return this.elements[head];
}
return Long.MAX_VALUE;
@@ -84,12 +83,12 @@ final class InvocationStack {
* Doubles the capacity of this deque
*/
private void doubleCapacity() {
- int oldCapacity = elements.length;
+ int oldCapacity = this.elements.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity < 0) {
throw new IllegalStateException("Sorry, deque too big");
}
- elements = Arrays.copyOf(elements, newCapacity);
+ this.elements = Arrays.copyOf(this.elements, newCapacity);
}
}
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/FlowGraph.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/FlowGraph.java
deleted file mode 100644
index f45be6cd..00000000
--- a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/FlowGraph.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2022 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.flow2;
-
-/**
- * A representation of a flow network. A flow network is a directed graph where each edge has a capacity and receives an
- * amount of flow that cannot exceed the edge's capacity.
- */
-public interface FlowGraph {
- /**
- * Return the {@link FlowEngine} driving the simulation of the graph.
- */
- FlowEngine getEngine();
-
- /**
- * Create a new {@link FlowStage} representing a node in the flow network.
- *
- * @param logic The logic for handling the events of the stage.
- */
- FlowStage newStage(FlowStageLogic logic);
-
- /**
- * Add an edge between the specified outlet port and inlet port in this graph.
- *
- * @param outlet The outlet of the source from which the flow originates.
- * @param inlet The inlet of the sink that should receive the flow.
- */
- void connect(Outlet outlet, Inlet inlet);
-
- /**
- * Disconnect the specified {@link Outlet} (if connected).
- *
- * @param outlet The outlet to disconnect.
- */
- void disconnect(Outlet outlet);
-
- /**
- * Disconnect the specified {@link Inlet} (if connected).
- *
- * @param inlet The inlet to disconnect.
- */
- void disconnect(Inlet inlet);
-}
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/FlowGraphInternal.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/FlowGraphInternal.java
deleted file mode 100644
index 0f608b60..00000000
--- a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/FlowGraphInternal.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright (c) 2022 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.flow2;
-
-/**
- * Interface implemented by {@link FlowGraph} implementations.
- */
-interface FlowGraphInternal extends FlowGraph {
- /**
- * Internal method to remove the specified {@link FlowStage} from the graph.
- */
- void detach(FlowStage stage);
-
- /**
- * Helper method to connect an outlet to an inlet.
- */
- static void connect(FlowGraph graph, Outlet outlet, Inlet inlet) {
- if (!(outlet instanceof OutPort) || !(inlet instanceof InPort)) {
- throw new IllegalArgumentException("Invalid outlet or inlet passed to graph");
- }
-
- InPort inPort = (InPort) inlet;
- OutPort outPort = (OutPort) outlet;
-
- if (!graph.equals(outPort.getGraph()) || !graph.equals(inPort.getGraph())) {
- throw new IllegalArgumentException("Outlet or inlet does not belong to graph");
- } else if (outPort.input != null || inPort.output != null) {
- throw new IllegalStateException("Inlet or outlet already connected");
- }
-
- outPort.input = inPort;
- inPort.output = outPort;
-
- inPort.connect();
- outPort.connect();
- }
-
- /**
- * Helper method to disconnect an outlet.
- */
- static void disconnect(FlowGraph graph, Outlet outlet) {
- if (!(outlet instanceof OutPort)) {
- throw new IllegalArgumentException("Invalid outlet passed to graph");
- }
-
- OutPort outPort = (OutPort) outlet;
-
- if (!graph.equals(outPort.getGraph())) {
- throw new IllegalArgumentException("Outlet or inlet does not belong to graph");
- }
-
- outPort.cancel(null);
- outPort.complete();
- }
-
- /**
- * Helper method to disconnect an inlet.
- */
- static void disconnect(FlowGraph graph, Inlet inlet) {
- if (!(inlet instanceof InPort)) {
- throw new IllegalArgumentException("Invalid outlet passed to graph");
- }
-
- InPort inPort = (InPort) inlet;
-
- if (!graph.equals(inPort.getGraph())) {
- throw new IllegalArgumentException("Outlet or inlet does not belong to graph");
- }
-
- inPort.finish(null);
- inPort.cancel(null);
- }
-}
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/FlowStage.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/FlowStage.java
deleted file mode 100644
index 25f87e04..00000000
--- a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/FlowStage.java
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- * Copyright (c) 2022 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.flow2;
-
-import java.time.InstantSource;
-import java.util.HashMap;
-import java.util.Map;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * A {@link FlowStage} represents a node in a {@link FlowGraph}.
- */
-public final class FlowStage {
- private static final Logger LOGGER = LoggerFactory.getLogger(FlowStage.class);
-
- /**
- * States of the flow stage.
- */
- private static final int STAGE_PENDING = 0; // Stage is pending to be started
-
- private static final int STAGE_ACTIVE = 1; // Stage is actively running
- private static final int STAGE_CLOSED = 2; // Stage is closed
- private static final int STAGE_STATE = 0b11; // Mask for accessing the state of the flow stage
-
- /**
- * Flags of the flow connection
- */
- private static final int STAGE_INVALIDATE = 1 << 2; // The stage is invalidated
-
- private static final int STAGE_CLOSE = 1 << 3; // The stage should be closed
- private static final int STAGE_UPDATE_ACTIVE = 1 << 4; // An update for the connection is active
- private static final int STAGE_UPDATE_PENDING = 1 << 5; // An (immediate) update of the connection is pending
-
- /**
- * The flags representing the state and pending actions for the stage.
- */
- private int flags = STAGE_PENDING;
-
- /**
- * The deadline of the stage after which an update should run.
- */
- long deadline = Long.MAX_VALUE;
-
- /**
- * The index of the timer in the {@link FlowTimerQueue}.
- */
- int timerIndex = -1;
-
- final InstantSource clock;
- private final FlowStageLogic logic;
- final FlowGraphInternal parentGraph;
- private final FlowEngine engine;
-
- private final Map<String, InPort> inlets = new HashMap<>();
- private final Map<String, OutPort> outlets = new HashMap<>();
- private int nextInlet = 0;
- private int nextOutlet = 0;
-
- /**
- * Construct a new {@link FlowStage} instance.
- *
- * @param parentGraph The {@link FlowGraph} this stage belongs to.
- * @param logic The logic of the stage.
- */
- FlowStage(FlowGraphInternal parentGraph, FlowStageLogic logic) {
- this.parentGraph = parentGraph;
- this.logic = logic;
- this.engine = parentGraph.getEngine();
- this.clock = engine.getClock();
- }
-
- /**
- * Return the {@link FlowGraph} to which this stage belongs.
- */
- public FlowGraph getGraph() {
- return parentGraph;
- }
-
- /**
- * Return the {@link Inlet} (an in-going edge) with the specified <code>name</code> for this {@link FlowStage}.
- * If an inlet with that name does not exist, a new one is allocated for the stage.
- *
- * @param name The name of the inlet.
- * @return The {@link InPort} representing an {@link Inlet} with the specified <code>name</code>.
- */
- public InPort getInlet(String name) {
- return inlets.computeIfAbsent(name, (key) -> new InPort(this, key, nextInlet++));
- }
-
- /**
- * Return the {@link Outlet} (an out-going edge) with the specified <code>name</code> for this {@link FlowStage}.
- * If an outlet with that name does not exist, a new one is allocated for the stage.
- *
- * @param name The name of the outlet.
- * @return The {@link OutPort} representing an {@link Outlet} with the specified <code>name</code>.
- */
- public OutPort getOutlet(String name) {
- return outlets.computeIfAbsent(name, (key) -> new OutPort(this, key, nextOutlet++));
- }
-
- /**
- * Return the current deadline of the {@link FlowStage}'s timer (in milliseconds after epoch).
- */
- public long getDeadline() {
- return deadline;
- }
-
- /**
- * Set the deadline of the {@link FlowStage}'s timer.
- *
- * @param deadline The new deadline (in milliseconds after epoch) when the stage should be interrupted.
- */
- public void setDeadline(long deadline) {
- this.deadline = deadline;
-
- if ((flags & STAGE_UPDATE_ACTIVE) == 0) {
- // Update the timer queue with the new deadline
- engine.scheduleDelayed(this);
- }
- }
-
- /**
- * Invalidate the {@link FlowStage} forcing the stage to update.
- */
- public void invalidate() {
- int flags = this.flags;
-
- if ((flags & STAGE_UPDATE_ACTIVE) == 0) {
- scheduleImmediate(clock.millis(), flags | STAGE_INVALIDATE);
- }
- }
-
- /**
- * Synchronously update the {@link FlowStage} at the current timestamp.
- */
- public void sync() {
- this.flags |= STAGE_INVALIDATE;
- onUpdate(clock.millis());
- engine.scheduleDelayed(this);
- }
-
- /**
- * Close the {@link FlowStage} and disconnect all inlets and outlets.
- */
- public void close() {
- int flags = this.flags;
-
- if ((flags & STAGE_STATE) == STAGE_CLOSED) {
- return;
- }
-
- // Toggle the close bit. In case no update is active, schedule a new update.
- if ((flags & STAGE_UPDATE_ACTIVE) != 0) {
- this.flags = flags | STAGE_CLOSE;
- } else {
- scheduleImmediate(clock.millis(), flags | STAGE_CLOSE);
- }
- }
-
- /**
- * Update the state of the flow stage.
- *
- * @param now The current virtual timestamp.
- */
- void onUpdate(long now) {
- int flags = this.flags;
- int state = flags & STAGE_STATE;
-
- if (state == STAGE_ACTIVE) {
- doUpdate(now, flags);
- } else if (state == STAGE_PENDING) {
- doStart(now, flags);
- }
- }
-
- /**
- * Invalidate the {@link FlowStage} forcing the stage to update.
- *
- * <p>
- * This method is similar to {@link #invalidate()}, but allows the user to manually pass the current timestamp to
- * prevent having to re-query the clock. This method should not be called during an update.
- */
- void invalidate(long now) {
- scheduleImmediate(now, flags | STAGE_INVALIDATE);
- }
-
- /**
- * Schedule an immediate update for this stage.
- */
- private void scheduleImmediate(long now, int flags) {
- // In case an immediate update is already scheduled, no need to do anything
- if ((flags & STAGE_UPDATE_PENDING) != 0) {
- this.flags = flags;
- return;
- }
-
- // Mark the stage that there is an update pending
- this.flags = flags | STAGE_UPDATE_PENDING;
-
- engine.scheduleImmediate(now, this);
- }
-
- /**
- * Start the stage.
- */
- private void doStart(long now, int flags) {
- // Update state before calling into the outside world, so it observes a consistent state
- flags = flags | STAGE_ACTIVE | STAGE_UPDATE_ACTIVE;
-
- doUpdate(now, flags);
- }
-
- /**
- * Update the state of the stage.
- */
- private void doUpdate(long now, int flags) {
- long deadline = this.deadline;
- long newDeadline = deadline;
-
- // Update the stage if:
- // (1) the timer of the stage has expired.
- // (2) one of the input ports is pushed,
- // (3) one of the output ports is pulled,
- if ((flags & STAGE_INVALIDATE) != 0 || deadline == now) {
- // Update state before calling into the outside world, so it observes a consistent state
- this.flags = (flags & ~STAGE_INVALIDATE) | STAGE_UPDATE_ACTIVE;
-
- try {
- newDeadline = logic.onUpdate(this, now);
-
- // IMPORTANT: Re-fetch the flags after the callback might have changed those
- flags = this.flags;
- } catch (Exception e) {
- doFail(e);
- }
- }
-
- // Check whether the stage is marked as closing.
- if ((flags & STAGE_CLOSE) != 0) {
- doClose(flags, null);
-
- // IMPORTANT: Re-fetch the flags after the callback might have changed those
- flags = this.flags;
- }
-
- // Indicate that no update is active anymore and flush the flags
- this.flags = flags & ~(STAGE_UPDATE_ACTIVE | STAGE_UPDATE_PENDING);
- this.deadline = newDeadline;
-
- // Update the timer queue with the new deadline
- engine.scheduleDelayedInContext(this);
- }
-
- /**
- * This method is invoked when an uncaught exception is caught by the engine. When this happens, the
- * {@link FlowStageLogic} "fails" and disconnects all its inputs and outputs.
- */
- void doFail(Throwable cause) {
- LOGGER.warn("Uncaught exception (closing stage)", cause);
-
- doClose(flags, cause);
- }
-
- /**
- * This method is invoked when the {@link FlowStageLogic} exits successfully or due to failure.
- */
- private void doClose(int flags, Throwable cause) {
- // Mark the stage as closed
- this.flags = flags & ~(STAGE_STATE | STAGE_INVALIDATE | STAGE_CLOSE) | STAGE_CLOSED;
-
- // Remove stage from parent graph
- parentGraph.detach(this);
-
- // Remove stage from the timer queue
- setDeadline(Long.MAX_VALUE);
-
- // Cancel all input ports
- for (InPort port : inlets.values()) {
- if (port != null) {
- port.cancel(cause);
- }
- }
-
- // Cancel all output ports
- for (OutPort port : outlets.values()) {
- if (port != null) {
- port.fail(cause);
- }
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/FlowStageLogic.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/FlowStageLogic.java
deleted file mode 100644
index 70986a35..00000000
--- a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/FlowStageLogic.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2022 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.flow2;
-
-/**
- * The {@link FlowStageLogic} interface is responsible for describing the behaviour of a {@link FlowStage} via
- * out-going flows based on its potential inputs.
- */
-public interface FlowStageLogic {
- /**
- * This method is invoked when the one of the stage's inlets or outlets is invalidated.
- *
- * @param ctx The context in which the stage runs.
- * @param now The virtual timestamp in milliseconds after epoch at which the update is occurring.
- * @return The next deadline for the stage.
- */
- long onUpdate(FlowStage ctx, long now);
-}
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/InHandler.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/InHandler.java
deleted file mode 100644
index 839b01db..00000000
--- a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/InHandler.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 2022 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.flow2;
-
-/**
- * Collection of callbacks for the input port (a {@link InPort}) of a {@link FlowStageLogic}.
- */
-public interface InHandler {
- /**
- * Return the actual flow rate over the input port.
- *
- * @param port The input port to which the flow was pushed.
- * @return The actual flow rate over the port.
- */
- default float getRate(InPort port) {
- return Math.min(port.getDemand(), port.getCapacity());
- }
-
- /**
- * This method is invoked when another {@link FlowStageLogic} changes the rate of flow to the specified inlet.
- *
- * @param port The input port to which the flow was pushed.
- * @param demand The rate of flow the output attempted to push to the port.
- */
- void onPush(InPort port, float demand);
-
- /**
- * This method is invoked when the input port is finished.
- *
- * @param port The input port that has finished.
- * @param cause The cause of the input port being finished or <code>null</code> if the port completed successfully.
- */
- void onUpstreamFinish(InPort port, Throwable cause);
-}
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/InHandlers.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/InHandlers.java
deleted file mode 100644
index 9d5b4bef..00000000
--- a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/InHandlers.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2022 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.flow2;
-
-/**
- * A collection of common {@link InHandler} implementations.
- */
-public class InHandlers {
- /**
- * Prevent construction of this class.
- */
- private InHandlers() {}
-
- /**
- * Return an {@link InHandler} that does nothing.
- */
- public static InHandler noop() {
- return NoopInHandler.INSTANCE;
- }
-
- /**
- * No-op implementation of {@link InHandler}.
- */
- private static final class NoopInHandler implements InHandler {
- public static final InHandler INSTANCE = new NoopInHandler();
-
- @Override
- public void onPush(InPort port, float demand) {}
-
- @Override
- public void onUpstreamFinish(InPort port, Throwable cause) {}
- }
-}
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/InPort.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/InPort.java
deleted file mode 100644
index 16fed4eb..00000000
--- a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/InPort.java
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * Copyright (c) 2022 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.flow2;
-
-import java.time.InstantSource;
-import java.util.Objects;
-
-/**
- * A port that consumes a flow.
- * <p>
- * Input ports are represented as in-going edges in the flow graph.
- */
-public final class InPort implements Inlet {
- private final int id;
-
- private float capacity;
- private float demand;
-
- private boolean mask;
-
- OutPort output;
- private InHandler handler = InHandlers.noop();
- private final InstantSource clock;
- private final String name;
- private final FlowStage stage;
-
- InPort(FlowStage stage, String name, int id) {
- this.name = name;
- this.id = id;
- this.stage = stage;
- this.clock = stage.clock;
- }
-
- @Override
- public FlowGraph getGraph() {
- return stage.parentGraph;
- }
-
- @Override
- public String getName() {
- return name;
- }
-
- /**
- * Return the identifier of the {@link InPort} with respect to its stage.
- */
- public int getId() {
- return id;
- }
-
- /**
- * Return the current capacity of the input port.
- */
- public float getCapacity() {
- return capacity;
- }
-
- /**
- * Return the current demand of flow of the input port.
- */
- public float getDemand() {
- return demand;
- }
-
- /**
- * Return the current rate of flow of the input port.
- */
- public float getRate() {
- return handler.getRate(this);
- }
-
- /**
- * Pull the flow with the specified <code>capacity</code> from the input port.
- *
- * @param capacity The maximum throughput that the stage can receive from the input port.
- */
- public void pull(float capacity) {
- this.capacity = capacity;
-
- OutPort output = this.output;
- if (output != null) {
- output.pull(capacity);
- }
- }
-
- /**
- * Return the current {@link InHandler} of the input port.
- */
- public InHandler getHandler() {
- return handler;
- }
-
- /**
- * Set the {@link InHandler} of the input port.
- */
- public void setHandler(InHandler handler) {
- this.handler = handler;
- }
-
- /**
- * Return the mask of this port.
- * <p>
- * Stages ignore events originating from masked ports.
- */
- public boolean getMask() {
- return mask;
- }
-
- /**
- * (Un)mask the port.
- */
- public void setMask(boolean mask) {
- this.mask = mask;
- }
-
- /**
- * Disconnect the input port from its (potentially) connected outlet.
- * <p>
- * The inlet can still be used and re-connected to another outlet.
- *
- * @param cause The cause for disconnecting the port or <code>null</code> when no more flow is needed.
- */
- public void cancel(Throwable cause) {
- demand = 0.f;
-
- OutPort output = this.output;
- if (output != null) {
- this.output = null;
- output.input = null;
- output.cancel(cause);
- }
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- InPort port = (InPort) o;
- return stage.equals(port.stage) && name.equals(port.name);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(stage.parentGraph, name);
- }
-
- /**
- * This method is invoked when the inlet is connected to an outlet.
- */
- void connect() {
- OutPort output = this.output;
- output.pull(capacity);
- }
-
- /**
- * Push a flow from an outlet to this inlet.
- *
- * @param demand The rate of flow to push.
- */
- void push(float demand) {
- // No-op when the rate is unchanged
- if (this.demand == demand) {
- return;
- }
-
- try {
- handler.onPush(this, demand);
- this.demand = demand;
-
- if (!mask) {
- stage.invalidate(clock.millis());
- }
- } catch (Exception e) {
- stage.doFail(e);
- }
- }
-
- /**
- * This method is invoked by the connected {@link OutPort} when it finishes.
- */
- void finish(Throwable cause) {
- try {
- long now = clock.millis();
- handler.onUpstreamFinish(this, cause);
- this.demand = 0.f;
-
- if (!mask) {
- stage.invalidate(now);
- }
- } catch (Exception e) {
- stage.doFail(e);
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/Inlet.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/Inlet.java
deleted file mode 100644
index 4a9ea6a5..00000000
--- a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/Inlet.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2022 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.flow2;
-
-/**
- * An in-going edge in a {@link FlowGraph}.
- */
-public interface Inlet {
- /**
- * Return the {@link FlowGraph} to which the inlet is exposed.
- */
- FlowGraph getGraph();
-
- /**
- * Return the name of the inlet.
- */
- String getName();
-}
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/OutHandler.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/OutHandler.java
deleted file mode 100644
index 723c6d6b..00000000
--- a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/OutHandler.java
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (c) 2022 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.flow2;
-
-/**
- * Collection of callbacks for the output port (a {@link OutPort}) of a {@link FlowStageLogic}.
- */
-public interface OutHandler {
- /**
- * This method is invoked when another {@link FlowStageLogic} changes the capacity of the outlet.
- *
- * @param port The output port of which the capacity was changed.
- * @param capacity The new capacity of the outlet.
- */
- void onPull(OutPort port, float capacity);
-
- /**
- * This method is invoked when the output port no longer accepts any flow.
- * <p>
- * After this callback no other callbacks will be called for this port.
- *
- * @param port The outlet that no longer accepts any flow.
- * @param cause The cause of the output port no longer accepting any flow or <code>null</code> if the port closed
- * successfully.
- */
- void onDownstreamFinish(OutPort port, Throwable cause);
-}
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/OutHandlers.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/OutHandlers.java
deleted file mode 100644
index 8fbfda0d..00000000
--- a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/OutHandlers.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2022 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.flow2;
-
-/**
- * A collection of common {@link OutHandler} implementations.
- */
-public class OutHandlers {
- /**
- * Prevent construction of this class.
- */
- private OutHandlers() {}
-
- /**
- * Return an {@link OutHandler} that does nothing.
- */
- public static OutHandler noop() {
- return NoopOutHandler.INSTANCE;
- }
-
- /**
- * No-op implementation of {@link OutHandler}.
- */
- private static final class NoopOutHandler implements OutHandler {
- public static final OutHandler INSTANCE = new NoopOutHandler();
-
- @Override
- public void onPull(OutPort port, float capacity) {}
-
- @Override
- public void onDownstreamFinish(OutPort port, Throwable cause) {}
- }
-}
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/OutPort.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/OutPort.java
deleted file mode 100644
index 1f7ed4ee..00000000
--- a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/OutPort.java
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright (c) 2022 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.flow2;
-
-import java.time.InstantSource;
-import java.util.Objects;
-
-/**
- * A port that outputs a flow.
- * <p>
- * Output ports are represented as out-going edges in the flow graph.
- */
-public final class OutPort implements Outlet {
- private final int id;
-
- private float capacity;
- private float demand;
-
- private boolean mask;
-
- InPort input;
- private OutHandler handler = OutHandlers.noop();
- private final String name;
- private final FlowStage stage;
- private final InstantSource clock;
-
- OutPort(FlowStage stage, String name, int id) {
- this.name = name;
- this.id = id;
- this.stage = stage;
- this.clock = stage.clock;
- }
-
- @Override
- public FlowGraph getGraph() {
- return stage.parentGraph;
- }
-
- @Override
- public String getName() {
- return name;
- }
-
- /**
- * Return the identifier of the {@link OutPort} with respect to its stage.
- */
- public int getId() {
- return id;
- }
-
- /**
- * Return the capacity of the output port.
- */
- public float getCapacity() {
- return capacity;
- }
-
- /**
- * Return the current demand of flow of the output port.
- */
- public float getDemand() {
- return demand;
- }
-
- /**
- * Return the current rate of flow of the input port.
- */
- public float getRate() {
- InPort input = this.input;
- if (input != null) {
- return input.getRate();
- }
-
- return 0.f;
- }
-
- /**
- * Return the current {@link OutHandler} of the output port.
- */
- public OutHandler getHandler() {
- return handler;
- }
-
- /**
- * Set the {@link OutHandler} of the output port.
- */
- public void setHandler(OutHandler handler) {
- this.handler = handler;
- }
-
- /**
- * Return the mask of this port.
- * <p>
- * Stages ignore events originating from masked ports.
- */
- public boolean getMask() {
- return mask;
- }
-
- /**
- * (Un)mask the port.
- */
- public void setMask(boolean mask) {
- this.mask = mask;
- }
-
- /**
- * Push the given flow rate over output port.
- *
- * @param rate The rate of the flow to push.
- */
- public void push(float rate) {
- demand = rate;
- InPort input = this.input;
-
- if (input != null) {
- input.push(rate);
- }
- }
-
- /**
- * Signal to the downstream port that the output has completed successfully and disconnect the port from its input.
- * <p>
- * The output port can still be used and re-connected to another input.
- */
- public void complete() {
- fail(null);
- }
-
- /**
- * Signal a failure to the downstream port and disconnect the port from its input.
- * <p>
- * The output can still be used and re-connected to another input.
- */
- public void fail(Throwable cause) {
- capacity = 0.f;
-
- InPort input = this.input;
- if (input != null) {
- this.input = null;
- input.output = null;
- input.finish(cause);
- }
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- OutPort port = (OutPort) o;
- return stage.equals(port.stage) && name.equals(port.name);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(stage.parentGraph, name);
- }
-
- /**
- * This method is invoked when the outlet is connected to an inlet.
- */
- void connect() {
- input.push(demand);
- }
-
- /**
- * Pull from this outlet with a specified capacity.
- *
- * @param capacity The capacity of the inlet.
- */
- void pull(float capacity) {
- // No-op when outlet is not active or the rate is unchanged
- if (this.capacity == capacity) {
- return;
- }
-
- try {
- handler.onPull(this, capacity);
- this.capacity = capacity;
-
- if (!mask) {
- stage.invalidate(clock.millis());
- }
- } catch (Exception e) {
- stage.doFail(e);
- }
- }
-
- /**
- * This method is invoked by the connected {@link InPort} when downstream cancels the connection.
- */
- void cancel(Throwable cause) {
- try {
- handler.onDownstreamFinish(this, cause);
- this.capacity = 0.f;
-
- if (!mask) {
- stage.invalidate(clock.millis());
- }
- } catch (Exception e) {
- stage.doFail(e);
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/mux/FlowMultiplexer.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/mux/FlowMultiplexer.java
deleted file mode 100644
index dec98955..00000000
--- a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/mux/FlowMultiplexer.java
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (c) 2022 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.flow2.mux;
-
-import org.opendc.simulator.flow2.FlowStageLogic;
-import org.opendc.simulator.flow2.Inlet;
-import org.opendc.simulator.flow2.Outlet;
-
-/**
- * A {@link FlowStageLogic} that multiplexes multiple inputs over (possibly) multiple outputs.
- */
-public interface FlowMultiplexer {
- /**
- * Return maximum number of inputs supported by the multiplexer.
- */
- int getMaxInputs();
-
- /**
- * Return maximum number of outputs supported by the multiplexer.
- */
- int getMaxOutputs();
-
- /**
- * Return the number of active inputs on this multiplexer.
- */
- int getInputCount();
-
- /**
- * Allocate a new input on this multiplexer with the specified capacity..
- *
- * @return The identifier of the input for this stage.
- */
- Inlet newInput();
-
- /**
- * Release the input at the specified slot.
- *
- * @param inlet The inlet to release.
- */
- void releaseInput(Inlet inlet);
-
- /**
- * Return the number of active outputs on this multiplexer.
- */
- int getOutputCount();
-
- /**
- * Allocate a new output on this multiplexer.
- *
- * @return The outlet for this stage.
- */
- Outlet newOutput();
-
- /**
- * Release the output at the specified slot.
- *
- * @param outlet The outlet to release.
- */
- void releaseOutput(Outlet outlet);
-
- /**
- * Return the total input capacity of the {@link FlowMultiplexer}.
- */
- float getCapacity();
-
- /**
- * Return the total input demand for the {@link FlowMultiplexer}.
- */
- float getDemand();
-
- /**
- * Return the total input rate for the {@link FlowMultiplexer}.
- */
- float getRate();
-}
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/mux/FlowMultiplexerFactory.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/mux/FlowMultiplexerFactory.java
deleted file mode 100644
index 0b5b9141..00000000
--- a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/mux/FlowMultiplexerFactory.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2022 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.flow2.mux;
-
-import org.opendc.simulator.flow2.FlowGraph;
-
-/**
- * Factory interface for a {@link FlowMultiplexer} implementation.
- */
-public interface FlowMultiplexerFactory {
- /**
- * Construct a new {@link FlowMultiplexer} belonging to the specified {@link FlowGraph}.
- *
- * @param graph The graph to which the multiplexer belongs.
- */
- FlowMultiplexer newMultiplexer(FlowGraph graph);
-
- /**
- * Return a {@link FlowMultiplexerFactory} for {@link ForwardingFlowMultiplexer} instances.
- */
- static FlowMultiplexerFactory forwardingMultiplexer() {
- return ForwardingFlowMultiplexer.FACTORY;
- }
-
- /**
- * Return a {@link FlowMultiplexerFactory} for {@link MaxMinFlowMultiplexer} instances.
- */
- static FlowMultiplexerFactory maxMinMultiplexer() {
- return MaxMinFlowMultiplexer.FACTORY;
- }
-}
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/mux/ForwardingFlowMultiplexer.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/mux/ForwardingFlowMultiplexer.java
deleted file mode 100644
index e0564cd2..00000000
--- a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/mux/ForwardingFlowMultiplexer.java
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * Copyright (c) 2022 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.flow2.mux;
-
-import java.util.Arrays;
-import java.util.BitSet;
-import org.opendc.simulator.flow2.FlowGraph;
-import org.opendc.simulator.flow2.FlowStage;
-import org.opendc.simulator.flow2.FlowStageLogic;
-import org.opendc.simulator.flow2.InHandler;
-import org.opendc.simulator.flow2.InPort;
-import org.opendc.simulator.flow2.Inlet;
-import org.opendc.simulator.flow2.OutHandler;
-import org.opendc.simulator.flow2.OutPort;
-import org.opendc.simulator.flow2.Outlet;
-
-/**
- * A {@link FlowMultiplexer} implementation that allocates inputs to the outputs of the multiplexer exclusively.
- * This means that a single input is directly connected to an output and that the multiplexer can only support as many
- * inputs as outputs.
- */
-public final class ForwardingFlowMultiplexer implements FlowMultiplexer, FlowStageLogic {
- /**
- * Factory implementation for this implementation.
- */
- static FlowMultiplexerFactory FACTORY = ForwardingFlowMultiplexer::new;
-
- public final IdleInHandler IDLE_IN_HANDLER = new IdleInHandler();
- public final IdleOutHandler IDLE_OUT_HANDLER = new IdleOutHandler();
-
- private final FlowStage stage;
-
- private InPort[] inlets;
- private OutPort[] outlets;
- private final BitSet activeInputs;
- private final BitSet activeOutputs;
- private final BitSet availableOutputs;
-
- private float capacity = 0.f;
- private float demand = 0.f;
-
- public ForwardingFlowMultiplexer(FlowGraph graph) {
- this.stage = graph.newStage(this);
-
- this.inlets = new InPort[4];
- this.activeInputs = new BitSet();
- this.outlets = new OutPort[4];
- this.activeOutputs = new BitSet();
- this.availableOutputs = new BitSet();
- }
-
- @Override
- public float getCapacity() {
- return capacity;
- }
-
- @Override
- public float getDemand() {
- return demand;
- }
-
- @Override
- public float getRate() {
- final BitSet activeOutputs = this.activeOutputs;
- final OutPort[] outlets = this.outlets;
- float rate = 0.f;
- for (int i = activeOutputs.nextSetBit(0); i != -1; i = activeOutputs.nextSetBit(i + 1)) {
- rate += outlets[i].getRate();
- }
- return rate;
- }
-
- @Override
- public int getMaxInputs() {
- return getOutputCount();
- }
-
- @Override
- public int getMaxOutputs() {
- return Integer.MAX_VALUE;
- }
-
- @Override
- public int getInputCount() {
- return activeInputs.length();
- }
-
- @Override
- public Inlet newInput() {
- final BitSet activeInputs = this.activeInputs;
- int slot = activeInputs.nextClearBit(0);
-
- InPort inPort = stage.getInlet("in" + slot);
- inPort.setMask(true);
-
- InPort[] inlets = this.inlets;
- if (slot >= inlets.length) {
- int newLength = inlets.length + (inlets.length >> 1);
- inlets = Arrays.copyOf(inlets, newLength);
- this.inlets = inlets;
- }
-
- final BitSet availableOutputs = this.availableOutputs;
- int outSlot = availableOutputs.nextSetBit(0);
-
- if (outSlot < 0) {
- throw new IllegalStateException("No capacity available for a new input");
- }
-
- inlets[slot] = inPort;
- activeInputs.set(slot);
-
- OutPort outPort = outlets[outSlot];
- availableOutputs.clear(outSlot);
-
- inPort.setHandler(new ForwardingInHandler(outPort));
- outPort.setHandler(new ForwardingOutHandler(inPort));
-
- inPort.pull(outPort.getCapacity());
-
- return inPort;
- }
-
- @Override
- public void releaseInput(Inlet inlet) {
- InPort port = (InPort) inlet;
- int slot = port.getId();
-
- final BitSet activeInputs = this.activeInputs;
-
- if (!activeInputs.get(slot)) {
- return;
- }
-
- port.cancel(null);
- activeInputs.clear(slot);
-
- ForwardingInHandler inHandler = (ForwardingInHandler) port.getHandler();
- availableOutputs.set(inHandler.output.getId());
-
- port.setHandler(IDLE_IN_HANDLER);
- }
-
- @Override
- public int getOutputCount() {
- return activeOutputs.length();
- }
-
- @Override
- public Outlet newOutput() {
- final BitSet activeOutputs = this.activeOutputs;
- int slot = activeOutputs.nextClearBit(0);
-
- OutPort port = stage.getOutlet("out" + slot);
- OutPort[] outlets = this.outlets;
- if (slot >= outlets.length) {
- int newLength = outlets.length + (outlets.length >> 1);
- outlets = Arrays.copyOf(outlets, newLength);
- this.outlets = outlets;
- }
- outlets[slot] = port;
-
- activeOutputs.set(slot);
- availableOutputs.set(slot);
-
- port.setHandler(IDLE_OUT_HANDLER);
-
- return port;
- }
-
- @Override
- public void releaseOutput(Outlet outlet) {
- OutPort port = (OutPort) outlet;
- int slot = port.getId();
- activeInputs.clear(slot);
- availableOutputs.clear(slot);
- port.complete();
-
- port.setHandler(IDLE_OUT_HANDLER);
- }
-
- @Override
- public long onUpdate(FlowStage ctx, long now) {
- return Long.MAX_VALUE;
- }
-
- class ForwardingInHandler implements InHandler {
- final OutPort output;
-
- ForwardingInHandler(OutPort output) {
- this.output = output;
- }
-
- @Override
- public float getRate(InPort port) {
- return output.getRate();
- }
-
- @Override
- public void onPush(InPort port, float rate) {
- ForwardingFlowMultiplexer.this.demand += -port.getDemand() + rate;
-
- output.push(rate);
- }
-
- @Override
- public void onUpstreamFinish(InPort port, Throwable cause) {
- ForwardingFlowMultiplexer.this.demand -= port.getDemand();
-
- final OutPort output = this.output;
- output.push(0.f);
-
- releaseInput(port);
- }
- }
-
- private class ForwardingOutHandler implements OutHandler {
- private final InPort input;
-
- ForwardingOutHandler(InPort input) {
- this.input = input;
- }
-
- @Override
- public void onPull(OutPort port, float capacity) {
- ForwardingFlowMultiplexer.this.capacity += -port.getCapacity() + capacity;
-
- input.pull(capacity);
- }
-
- @Override
- public void onDownstreamFinish(OutPort port, Throwable cause) {
- ForwardingFlowMultiplexer.this.capacity -= port.getCapacity();
-
- input.cancel(cause);
-
- releaseOutput(port);
- }
- }
-
- private static class IdleInHandler implements InHandler {
- @Override
- public float getRate(InPort port) {
- return 0.f;
- }
-
- @Override
- public void onPush(InPort port, float rate) {
- port.cancel(new IllegalStateException("Inlet is not allocated"));
- }
-
- @Override
- public void onUpstreamFinish(InPort port, Throwable cause) {}
- }
-
- private class IdleOutHandler implements OutHandler {
- @Override
- public void onPull(OutPort port, float capacity) {
- ForwardingFlowMultiplexer.this.capacity += -port.getCapacity() + capacity;
- }
-
- @Override
- public void onDownstreamFinish(OutPort port, Throwable cause) {
- ForwardingFlowMultiplexer.this.capacity -= port.getCapacity();
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/mux/MaxMinFlowMultiplexer.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/mux/MaxMinFlowMultiplexer.java
deleted file mode 100644
index ac5c4f5c..00000000
--- a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/mux/MaxMinFlowMultiplexer.java
+++ /dev/null
@@ -1,297 +0,0 @@
-/*
- * Copyright (c) 2022 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.flow2.mux;
-
-import java.util.Arrays;
-import java.util.BitSet;
-import org.opendc.simulator.flow2.FlowGraph;
-import org.opendc.simulator.flow2.FlowStage;
-import org.opendc.simulator.flow2.FlowStageLogic;
-import org.opendc.simulator.flow2.InHandler;
-import org.opendc.simulator.flow2.InPort;
-import org.opendc.simulator.flow2.Inlet;
-import org.opendc.simulator.flow2.OutHandler;
-import org.opendc.simulator.flow2.OutPort;
-import org.opendc.simulator.flow2.Outlet;
-
-/**
- * A {@link FlowMultiplexer} implementation that distributes the available capacity of the outputs over the inputs
- * using max-min fair sharing.
- * <p>
- * The max-min fair sharing algorithm of this multiplexer ensures that each input receives a fair share of the combined
- * output capacity, but allows individual inputs to use more capacity if there is still capacity left.
- */
-public final class MaxMinFlowMultiplexer implements FlowMultiplexer, FlowStageLogic {
- /**
- * Factory implementation for this implementation.
- */
- static FlowMultiplexerFactory FACTORY = MaxMinFlowMultiplexer::new;
-
- private final FlowStage stage;
- private final BitSet activeInputs;
- private final BitSet activeOutputs;
-
- private float capacity = 0.f;
- private float demand = 0.f;
- private float rate = 0.f;
-
- private InPort[] inlets;
- private long[] inputs;
- private float[] rates;
- private OutPort[] outlets;
-
- private final MultiplexerInHandler inHandler = new MultiplexerInHandler();
- private final MultiplexerOutHandler outHandler = new MultiplexerOutHandler();
-
- /**
- * Construct a {@link MaxMinFlowMultiplexer} instance.
- *
- * @param graph The {@link FlowGraph} to add the multiplexer to.
- */
- public MaxMinFlowMultiplexer(FlowGraph graph) {
- this.stage = graph.newStage(this);
- this.activeInputs = new BitSet();
- this.activeOutputs = new BitSet();
-
- this.inlets = new InPort[4];
- this.inputs = new long[4];
- this.rates = new float[4];
- this.outlets = new OutPort[4];
- }
-
- @Override
- public float getCapacity() {
- return capacity;
- }
-
- @Override
- public float getDemand() {
- return demand;
- }
-
- @Override
- public float getRate() {
- return rate;
- }
-
- @Override
- public int getMaxInputs() {
- return Integer.MAX_VALUE;
- }
-
- @Override
- public int getMaxOutputs() {
- return Integer.MAX_VALUE;
- }
-
- @Override
- public long onUpdate(FlowStage ctx, long now) {
- float capacity = this.capacity;
- float demand = this.demand;
- float rate = demand;
-
- if (demand > capacity) {
- rate = redistributeCapacity(inlets, inputs, rates, capacity);
- }
-
- if (this.rate != rate) {
- // Only update the outputs if the output rate has changed
- this.rate = rate;
-
- changeRate(activeOutputs, outlets, capacity, rate);
- }
-
- return Long.MAX_VALUE;
- }
-
- @Override
- public int getInputCount() {
- return activeInputs.length();
- }
-
- @Override
- public Inlet newInput() {
- final BitSet activeInputs = this.activeInputs;
- int slot = activeInputs.nextClearBit(0);
-
- InPort port = stage.getInlet("in" + slot);
- port.setHandler(inHandler);
- port.pull(this.capacity);
-
- InPort[] inlets = this.inlets;
- if (slot >= inlets.length) {
- int newLength = inlets.length + (inlets.length >> 1);
- inlets = Arrays.copyOf(inlets, newLength);
- inputs = Arrays.copyOf(inputs, newLength);
- rates = Arrays.copyOf(rates, newLength);
- this.inlets = inlets;
- }
- inlets[slot] = port;
-
- activeInputs.set(slot);
- return port;
- }
-
- @Override
- public void releaseInput(Inlet inlet) {
- InPort port = (InPort) inlet;
-
- activeInputs.clear(port.getId());
- port.cancel(null);
- }
-
- @Override
- public int getOutputCount() {
- return activeOutputs.length();
- }
-
- @Override
- public Outlet newOutput() {
- final BitSet activeOutputs = this.activeOutputs;
- int slot = activeOutputs.nextClearBit(0);
-
- OutPort port = stage.getOutlet("out" + slot);
- port.setHandler(outHandler);
-
- OutPort[] outlets = this.outlets;
- if (slot >= outlets.length) {
- int newLength = outlets.length + (outlets.length >> 1);
- outlets = Arrays.copyOf(outlets, newLength);
- this.outlets = outlets;
- }
- outlets[slot] = port;
-
- activeOutputs.set(slot);
- return port;
- }
-
- @Override
- public void releaseOutput(Outlet outlet) {
- OutPort port = (OutPort) outlet;
- activeInputs.clear(port.getId());
- port.complete();
- }
-
- /**
- * Helper function to redistribute the specified capacity across the inlets.
- */
- private static float redistributeCapacity(InPort[] inlets, long[] inputs, float[] rates, float capacity) {
- // If the demand is higher than the capacity, we need use max-min fair sharing to distribute the
- // constrained capacity across the inputs.
- for (int i = 0; i < inputs.length; i++) {
- InPort inlet = inlets[i];
- if (inlet == null) {
- break;
- }
-
- inputs[i] = ((long) Float.floatToRawIntBits(inlet.getDemand()) << 32) | (i & 0xFFFFFFFFL);
- }
- Arrays.sort(inputs);
-
- float availableCapacity = capacity;
- int inputSize = inputs.length;
-
- // Divide the available output capacity fairly over the inputs using max-min fair sharing
- for (int i = 0; i < inputs.length; i++) {
- long v = inputs[i];
- int slot = (int) v;
- float d = Float.intBitsToFloat((int) (v >> 32));
-
- if (d == 0.0) {
- continue;
- }
-
- float availableShare = availableCapacity / (inputSize - i);
- float r = Math.min(d, availableShare);
-
- rates[slot] = r;
- availableCapacity -= r;
- }
-
- return capacity - availableCapacity;
- }
-
- /**
- * Helper method to change the rate of the outlets.
- */
- private static void changeRate(BitSet activeOutputs, OutPort[] outlets, float capacity, float rate) {
- // Divide the requests over the available capacity of the input resources fairly
- for (int i = activeOutputs.nextSetBit(0); i != -1; i = activeOutputs.nextSetBit(i + 1)) {
- OutPort outlet = outlets[i];
- float fraction = outlet.getCapacity() / capacity;
- outlet.push(rate * fraction);
- }
- }
-
- /**
- * A {@link InHandler} implementation for the multiplexer inputs.
- */
- private class MultiplexerInHandler implements InHandler {
- @Override
- public float getRate(InPort port) {
- return rates[port.getId()];
- }
-
- @Override
- public void onPush(InPort port, float demand) {
- MaxMinFlowMultiplexer.this.demand += -port.getDemand() + demand;
- rates[port.getId()] = demand;
- }
-
- @Override
- public void onUpstreamFinish(InPort port, Throwable cause) {
- MaxMinFlowMultiplexer.this.demand -= port.getDemand();
- releaseInput(port);
- rates[port.getId()] = 0.f;
- }
- }
-
- /**
- * A {@link OutHandler} implementation for the multiplexer outputs.
- */
- private class MultiplexerOutHandler implements OutHandler {
- @Override
- public void onPull(OutPort port, float capacity) {
- float newCapacity = MaxMinFlowMultiplexer.this.capacity - port.getCapacity() + capacity;
- MaxMinFlowMultiplexer.this.capacity = newCapacity;
- changeInletCapacity(newCapacity);
- }
-
- @Override
- public void onDownstreamFinish(OutPort port, Throwable cause) {
- float newCapacity = MaxMinFlowMultiplexer.this.capacity - port.getCapacity();
- MaxMinFlowMultiplexer.this.capacity = newCapacity;
- releaseOutput(port);
- changeInletCapacity(newCapacity);
- }
-
- private void changeInletCapacity(float capacity) {
- BitSet activeInputs = MaxMinFlowMultiplexer.this.activeInputs;
- InPort[] inlets = MaxMinFlowMultiplexer.this.inlets;
-
- for (int i = activeInputs.nextSetBit(0); i != -1; i = activeInputs.nextSetBit(i + 1)) {
- inlets[i].pull(capacity);
- }
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/sink/FlowSink.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/sink/FlowSink.java
deleted file mode 100644
index 69c94708..00000000
--- a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/sink/FlowSink.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2022 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.flow2.sink;
-
-import org.opendc.simulator.flow2.FlowStage;
-import org.opendc.simulator.flow2.Inlet;
-
-/**
- * A {@link FlowStage} with a single input.
- */
-public interface FlowSink {
- /**
- * Return the input of this {@link FlowSink}.
- */
- Inlet getInput();
-}
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/sink/SimpleFlowSink.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/sink/SimpleFlowSink.java
deleted file mode 100644
index fdfe5ee8..00000000
--- a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/sink/SimpleFlowSink.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (c) 2022 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.flow2.sink;
-
-import org.opendc.simulator.flow2.FlowGraph;
-import org.opendc.simulator.flow2.FlowStage;
-import org.opendc.simulator.flow2.FlowStageLogic;
-import org.opendc.simulator.flow2.InHandler;
-import org.opendc.simulator.flow2.InPort;
-import org.opendc.simulator.flow2.Inlet;
-
-/**
- * A sink with a fixed capacity.
- */
-public final class SimpleFlowSink implements FlowSink, FlowStageLogic {
- private final FlowStage stage;
- private final InPort input;
- private final Handler handler;
-
- /**
- * Construct a new {@link SimpleFlowSink} with the specified initial capacity.
- *
- * @param graph The graph to add the sink to.
- * @param initialCapacity The initial capacity of the sink.
- */
- public SimpleFlowSink(FlowGraph graph, float initialCapacity) {
- this.stage = graph.newStage(this);
- this.handler = new Handler();
- this.input = stage.getInlet("in");
- this.input.pull(initialCapacity);
- this.input.setMask(true);
- this.input.setHandler(handler);
- }
-
- /**
- * Return the {@link Inlet} of this sink.
- */
- @Override
- public Inlet getInput() {
- return input;
- }
-
- /**
- * Return the capacity of the sink.
- */
- public float getCapacity() {
- return input.getCapacity();
- }
-
- /**
- * Update the capacity of the sink.
- *
- * @param capacity The new capacity to update the sink to.
- */
- public void setCapacity(float capacity) {
- input.pull(capacity);
- stage.invalidate();
- }
-
- /**
- * Return the flow rate of the sink.
- */
- public float getRate() {
- return input.getRate();
- }
-
- /**
- * Remove this node from the graph.
- */
- public void close() {
- stage.close();
- }
-
- @Override
- public long onUpdate(FlowStage ctx, long now) {
- InPort input = this.input;
- handler.rate = Math.min(input.getDemand(), input.getCapacity());
- return Long.MAX_VALUE;
- }
-
- /**
- * The {@link InHandler} implementation for the sink.
- */
- private static final class Handler implements InHandler {
- float rate;
-
- @Override
- public float getRate(InPort port) {
- return rate;
- }
-
- @Override
- public void onPush(InPort port, float demand) {
- float capacity = port.getCapacity();
- rate = Math.min(demand, capacity);
- }
-
- @Override
- public void onUpstreamFinish(InPort port, Throwable cause) {
- rate = 0.f;
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/source/EmptyFlowSource.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/source/EmptyFlowSource.java
deleted file mode 100644
index 2dcc66e4..00000000
--- a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/source/EmptyFlowSource.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (c) 2022 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.flow2.source;
-
-import org.opendc.simulator.flow2.FlowGraph;
-import org.opendc.simulator.flow2.FlowStage;
-import org.opendc.simulator.flow2.FlowStageLogic;
-import org.opendc.simulator.flow2.OutPort;
-import org.opendc.simulator.flow2.Outlet;
-
-/**
- * An empty {@link FlowSource}.
- */
-public final class EmptyFlowSource implements FlowSource, FlowStageLogic {
- private final FlowStage stage;
- private final OutPort output;
-
- /**
- * Construct a new {@link EmptyFlowSource}.
- */
- public EmptyFlowSource(FlowGraph graph) {
- this.stage = graph.newStage(this);
- this.output = stage.getOutlet("out");
- }
-
- /**
- * Return the {@link Outlet} of the source.
- */
- @Override
- public Outlet getOutput() {
- return output;
- }
-
- /**
- * Remove this node from the graph.
- */
- public void close() {
- stage.close();
- }
-
- @Override
- public long onUpdate(FlowStage ctx, long now) {
- return Long.MAX_VALUE;
- }
-}
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/source/FlowSource.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/source/FlowSource.java
deleted file mode 100644
index f9432c33..00000000
--- a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/source/FlowSource.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2022 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.flow2.source;
-
-import org.opendc.simulator.flow2.FlowStage;
-import org.opendc.simulator.flow2.Outlet;
-
-/**
- * A {@link FlowStage} with a single output.
- */
-public interface FlowSource {
- /**
- * Return the output of this {@link FlowSource}.
- */
- Outlet getOutput();
-}
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/source/RuntimeFlowSource.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/source/RuntimeFlowSource.java
deleted file mode 100644
index c09987cd..00000000
--- a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/source/RuntimeFlowSource.java
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright (c) 2022 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.flow2.source;
-
-import java.util.function.Consumer;
-import org.opendc.simulator.flow2.FlowGraph;
-import org.opendc.simulator.flow2.FlowStage;
-import org.opendc.simulator.flow2.FlowStageLogic;
-import org.opendc.simulator.flow2.OutHandler;
-import org.opendc.simulator.flow2.OutPort;
-import org.opendc.simulator.flow2.Outlet;
-
-/**
- * A {@link FlowSource} that ensures a flow is emitted for a specified amount of time at some utilization.
- */
-public class RuntimeFlowSource implements FlowSource, FlowStageLogic {
- private final float utilization;
-
- private final FlowStage stage;
- private final OutPort output;
- private final Consumer<RuntimeFlowSource> completionHandler;
-
- private long duration;
- private long lastPull;
-
- /**
- * Construct a {@link RuntimeFlowSource} instance.
- *
- * @param graph The {@link FlowGraph} to which this source belongs.
- * @param duration The duration of the source.
- * @param utilization The utilization of the capacity of the outlet.
- * @param completionHandler A callback invoked when the source completes.
- */
- public RuntimeFlowSource(
- FlowGraph graph, long duration, float utilization, Consumer<RuntimeFlowSource> completionHandler) {
- if (duration <= 0) {
- throw new IllegalArgumentException("Duration must be positive and non-zero");
- }
-
- if (utilization <= 0.0) {
- throw new IllegalArgumentException("Utilization must be positive and non-zero");
- }
-
- this.stage = graph.newStage(this);
- this.output = stage.getOutlet("out");
- this.output.setHandler(new OutHandler() {
- @Override
- public void onPull(OutPort port, float capacity) {}
-
- @Override
- public void onDownstreamFinish(OutPort port, Throwable cause) {
- // Source cannot complete without re-connecting to another sink, so mark the source as completed
- completionHandler.accept(RuntimeFlowSource.this);
- }
- });
- this.duration = duration;
- this.utilization = utilization;
- this.completionHandler = completionHandler;
- this.lastPull = graph.getEngine().getClock().millis();
- }
-
- /**
- * Construct a new {@link RuntimeFlowSource}.
- *
- * @param graph The {@link FlowGraph} to which this source belongs.
- * @param duration The duration of the source.
- * @param utilization The utilization of the capacity of the outlet.
- */
- public RuntimeFlowSource(FlowGraph graph, long duration, float utilization) {
- this(graph, duration, utilization, RuntimeFlowSource::close);
- }
-
- /**
- * Return the {@link Outlet} of the source.
- */
- @Override
- public Outlet getOutput() {
- return output;
- }
-
- /**
- * Remove this node from the graph.
- */
- public void close() {
- stage.close();
- }
-
- @Override
- public long onUpdate(FlowStage ctx, long now) {
- long lastPull = this.lastPull;
- this.lastPull = now;
-
- long delta = Math.max(0, now - lastPull);
-
- OutPort output = this.output;
- float limit = output.getCapacity() * utilization;
- long duration = this.duration - delta;
-
- if (duration <= 0) {
- completionHandler.accept(this);
- return Long.MAX_VALUE;
- }
-
- this.duration = duration;
- output.push(limit);
- return now + duration;
- }
-}
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/source/SimpleFlowSource.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/source/SimpleFlowSource.java
deleted file mode 100644
index a0e9cb9d..00000000
--- a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/source/SimpleFlowSource.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (c) 2022 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.flow2.source;
-
-import java.util.function.Consumer;
-import org.opendc.simulator.flow2.FlowGraph;
-import org.opendc.simulator.flow2.FlowStage;
-import org.opendc.simulator.flow2.FlowStageLogic;
-import org.opendc.simulator.flow2.OutHandler;
-import org.opendc.simulator.flow2.OutPort;
-import org.opendc.simulator.flow2.Outlet;
-
-/**
- * A flow source that contains a fixed amount and is pushed with a given utilization.
- */
-public final class SimpleFlowSource implements FlowSource, FlowStageLogic {
- private final float utilization;
- private float remainingAmount;
- private long lastPull;
-
- private final FlowStage stage;
- private final OutPort output;
- private final Consumer<SimpleFlowSource> completionHandler;
-
- /**
- * Construct a new {@link SimpleFlowSource}.
- *
- * @param graph The {@link FlowGraph} to which this source belongs.
- * @param amount The amount to transfer via the outlet.
- * @param utilization The utilization of the capacity of the outlet.
- * @param completionHandler A callback invoked when the source completes.
- */
- public SimpleFlowSource(
- FlowGraph graph, float amount, float utilization, Consumer<SimpleFlowSource> completionHandler) {
- if (amount < 0.0) {
- throw new IllegalArgumentException("Amount must be non-negative");
- }
-
- if (utilization <= 0.0) {
- throw new IllegalArgumentException("Utilization must be positive and non-zero");
- }
-
- this.stage = graph.newStage(this);
- this.output = stage.getOutlet("out");
- this.output.setHandler(new OutHandler() {
- @Override
- public void onPull(OutPort port, float capacity) {}
-
- @Override
- public void onDownstreamFinish(OutPort port, Throwable cause) {
- // Source cannot complete without re-connecting to another sink, so mark the source as completed
- completionHandler.accept(SimpleFlowSource.this);
- }
- });
- this.completionHandler = completionHandler;
- this.utilization = utilization;
- this.remainingAmount = amount;
- this.lastPull = graph.getEngine().getClock().millis();
- }
-
- /**
- * Construct a new {@link SimpleFlowSource}.
- *
- * @param graph The {@link FlowGraph} to which this source belongs.
- * @param amount The amount to transfer via the outlet.
- * @param utilization The utilization of the capacity of the outlet.
- */
- public SimpleFlowSource(FlowGraph graph, float amount, float utilization) {
- this(graph, amount, utilization, SimpleFlowSource::close);
- }
-
- /**
- * Return the {@link Outlet} of the source.
- */
- @Override
- public Outlet getOutput() {
- return output;
- }
-
- /**
- * Remove this node from the graph.
- */
- public void close() {
- stage.close();
- }
-
- @Override
- public long onUpdate(FlowStage ctx, long now) {
- long lastPull = this.lastPull;
- this.lastPull = now;
-
- long delta = Math.max(0, now - lastPull);
-
- OutPort output = this.output;
- float consumed = output.getRate() * delta / 1000.f;
- float limit = output.getCapacity() * utilization;
-
- float remainingAmount = this.remainingAmount - consumed;
- this.remainingAmount = remainingAmount;
-
- long duration = (long) Math.ceil(remainingAmount / limit * 1000);
-
- if (duration <= 0) {
- completionHandler.accept(this);
- return Long.MAX_VALUE;
- }
-
- output.push(limit);
- return now + duration;
- }
-}
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/source/TraceFlowSource.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/source/TraceFlowSource.java
deleted file mode 100644
index e8abc2d7..00000000
--- a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/source/TraceFlowSource.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (c) 2022 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.flow2.source;
-
-import java.util.function.Consumer;
-import org.opendc.simulator.flow2.FlowGraph;
-import org.opendc.simulator.flow2.FlowStage;
-import org.opendc.simulator.flow2.FlowStageLogic;
-import org.opendc.simulator.flow2.OutHandler;
-import org.opendc.simulator.flow2.OutPort;
-import org.opendc.simulator.flow2.Outlet;
-
-/**
- * A flow source that replays a sequence of fragments, each indicating the flow rate for some period of time.
- */
-public final class TraceFlowSource implements FlowSource, FlowStageLogic {
- private final OutPort output;
- private final long[] deadlines;
- private final float[] usages;
- private final int size;
- private int index;
-
- private final FlowStage stage;
- private final Consumer<TraceFlowSource> completionHandler;
-
- /**
- * Construct a {@link TraceFlowSource}.
- *
- * @param graph The {@link FlowGraph} to which the source belongs.
- * @param trace The {@link Trace} to replay.
- * @param completionHandler The completion handler to invoke when the source finishes.
- */
- public TraceFlowSource(FlowGraph graph, Trace trace, Consumer<TraceFlowSource> completionHandler) {
- this.stage = graph.newStage(this);
- this.output = stage.getOutlet("out");
- this.output.setHandler(new OutHandler() {
- @Override
- public void onPull(OutPort port, float capacity) {}
-
- @Override
- public void onDownstreamFinish(OutPort port, Throwable cause) {
- // Source cannot complete without re-connecting to another sink, so mark the source as completed
- completionHandler.accept(TraceFlowSource.this);
- }
- });
- this.deadlines = trace.deadlines;
- this.usages = trace.usages;
- this.size = trace.size;
- this.completionHandler = completionHandler;
- }
-
- /**
- * Construct a {@link TraceFlowSource}.
- *
- * @param graph The {@link FlowGraph} to which the source belongs.
- * @param trace The {@link Trace} to replay.
- */
- public TraceFlowSource(FlowGraph graph, Trace trace) {
- this(graph, trace, TraceFlowSource::close);
- }
-
- @Override
- public Outlet getOutput() {
- return output;
- }
-
- /**
- * Remove this node from the graph.
- */
- public void close() {
- stage.close();
- }
-
- @Override
- public long onUpdate(FlowStage ctx, long now) {
- int size = this.size;
- int index = this.index;
- long[] deadlines = this.deadlines;
- long deadline;
-
- do {
- deadline = deadlines[index];
- } while (deadline <= now && ++index < size);
-
- if (index >= size) {
- output.push(0.0f);
- completionHandler.accept(this);
- return Long.MAX_VALUE;
- }
-
- this.index = index;
- float usage = usages[index];
- output.push(usage);
-
- return deadline;
- }
-
- /**
- * A trace describes the workload over time.
- */
- public static final class Trace {
- private final long[] deadlines;
- private final float[] usages;
- private final int size;
-
- /**
- * Construct a {@link Trace}.
- *
- * @param deadlines The deadlines of the trace fragments.
- * @param usages The usages of the trace fragments.
- * @param size The size of the trace.
- */
- public Trace(long[] deadlines, float[] usages, int size) {
- this.deadlines = deadlines;
- this.usages = usages;
- this.size = size;
- }
-
- public long[] getDeadlines() {
- return deadlines;
- }
-
- public float[] getUsages() {
- return usages;
- }
-
- public int getSize() {
- return size;
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/util/FlowTransform.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/util/FlowTransform.java
deleted file mode 100644
index 51ea7df3..00000000
--- a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/util/FlowTransform.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2022 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.flow2.util;
-
-import org.opendc.simulator.flow2.FlowGraph;
-
-/**
- * A {@link FlowTransform} describes a transformation between two components in a {@link FlowGraph} that might operate
- * at different units of flow.
- */
-public interface FlowTransform {
- /**
- * Apply the transform to the specified flow rate.
- */
- float apply(float value);
-
- /**
- * Apply the inverse of the transformation to the specified flow rate.
- */
- float applyInverse(float value);
-}
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/util/FlowTransformer.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/util/FlowTransformer.java
deleted file mode 100644
index 852240d8..00000000
--- a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/util/FlowTransformer.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Copyright (c) 2022 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.flow2.util;
-
-import org.opendc.simulator.flow2.*;
-import org.opendc.simulator.flow2.sink.FlowSink;
-import org.opendc.simulator.flow2.source.FlowSource;
-
-/**
- * Helper class to transform flow from outlet to inlet.
- */
-public final class FlowTransformer implements FlowStageLogic, FlowSource, FlowSink {
- private final FlowStage stage;
- private final InPort input;
- private final OutPort output;
-
- /**
- * Construct a new {@link FlowTransformer}.
- */
- public FlowTransformer(FlowGraph graph, FlowTransform transform) {
- this.stage = graph.newStage(this);
- this.input = stage.getInlet("in");
- this.output = stage.getOutlet("out");
-
- this.input.setHandler(new ForwardInHandler(output, transform));
- this.input.setMask(true);
- this.output.setHandler(new ForwardOutHandler(input, transform));
- this.output.setMask(true);
- }
-
- /**
- * Return the {@link Outlet} of the transformer.
- */
- @Override
- public Outlet getOutput() {
- return output;
- }
-
- /**
- * Return the {@link Inlet} of the transformer.
- */
- @Override
- public Inlet getInput() {
- return input;
- }
-
- /**
- * Close the transformer.
- */
- void close() {
- stage.close();
- }
-
- @Override
- public long onUpdate(FlowStage ctx, long now) {
- return Long.MAX_VALUE;
- }
-
- private static class ForwardInHandler implements InHandler {
- private final OutPort output;
- private final FlowTransform transform;
-
- ForwardInHandler(OutPort output, FlowTransform transform) {
- this.output = output;
- this.transform = transform;
- }
-
- @Override
- public float getRate(InPort port) {
- return transform.applyInverse(output.getRate());
- }
-
- @Override
- public void onPush(InPort port, float demand) {
- float rate = transform.apply(demand);
- output.push(rate);
- }
-
- @Override
- public void onUpstreamFinish(InPort port, Throwable cause) {
- output.fail(cause);
- }
- }
-
- private static class ForwardOutHandler implements OutHandler {
- private final InPort input;
- private final FlowTransform transform;
-
- ForwardOutHandler(InPort input, FlowTransform transform) {
- this.input = input;
- this.transform = transform;
- }
-
- @Override
- public void onPull(OutPort port, float capacity) {
- input.pull(transform.applyInverse(capacity));
- }
-
- @Override
- public void onDownstreamFinish(OutPort port, Throwable cause) {
- input.cancel(cause);
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/util/FlowTransforms.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/util/FlowTransforms.java
deleted file mode 100644
index 428dbfca..00000000
--- a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/flow2/util/FlowTransforms.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (c) 2022 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.flow2.util;
-
-/**
- * A collection of common {@link FlowTransform} implementations.
- */
-public class FlowTransforms {
- /**
- * Prevent construction of this class.
- */
- private FlowTransforms() {}
-
- /**
- * Return a {@link FlowTransform} that forwards the flow rate unmodified.
- */
- public static FlowTransform noop() {
- return NoopFlowTransform.INSTANCE;
- }
-
- /**
- * No-op implementation of a {@link FlowTransform}.
- */
- private static final class NoopFlowTransform implements FlowTransform {
- static final NoopFlowTransform INSTANCE = new NoopFlowTransform();
-
- @Override
- public float apply(float value) {
- return value;
- }
-
- @Override
- public float applyInverse(float value) {
- return value;
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/InvocationStackTest.kt b/opendc-simulator/opendc-simulator-flow/src/test/kotlin/InvocationStackTest.kt
index 2250fe87..7744d7b2 100644
--- a/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/InvocationStackTest.kt
+++ b/opendc-simulator/opendc-simulator-flow/src/test/kotlin/InvocationStackTest.kt
@@ -20,12 +20,11 @@
* SOFTWARE.
*/
-package org.opendc.simulator.flow2
-
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertFalse
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test
+import org.opendc.simulator.engine.InvocationStack
/**
* Test suite for the [InvocationStack] class.
diff --git a/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/FlowEngineTest.kt b/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/FlowEngineTest.kt
deleted file mode 100644
index 413a5878..00000000
--- a/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/FlowEngineTest.kt
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Copyright (c) 2022 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.flow2
-
-import io.mockk.mockk
-import org.junit.jupiter.api.Assertions.assertEquals
-import org.junit.jupiter.api.Assertions.assertNotEquals
-import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.assertThrows
-import org.opendc.simulator.flow2.mux.MaxMinFlowMultiplexer
-import org.opendc.simulator.flow2.sink.SimpleFlowSink
-import org.opendc.simulator.flow2.source.SimpleFlowSource
-import org.opendc.simulator.kotlin.runSimulation
-
-/**
- * Smoke tests for the Flow API.
- */
-class FlowEngineTest {
- @Test
- fun testSmoke() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val multiplexer = MaxMinFlowMultiplexer(graph)
- val sink = SimpleFlowSink(graph, 2.0f)
-
- graph.connect(multiplexer.newOutput(), sink.input)
-
- val sourceA = SimpleFlowSource(graph, 2000.0f, 0.8f)
- val sourceB = SimpleFlowSource(graph, 2000.0f, 0.8f)
-
- graph.connect(sourceA.output, multiplexer.newInput())
- graph.connect(sourceB.output, multiplexer.newInput())
- }
-
- @Test
- fun testConnectInvalidInlet() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val inlet = mockk<Inlet>()
- val source = SimpleFlowSource(graph, 2000.0f, 0.8f)
- assertThrows<IllegalArgumentException> { graph.connect(source.output, inlet) }
- }
-
- @Test
- fun testConnectInvalidOutlet() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val outlet = mockk<Outlet>()
- val sink = SimpleFlowSink(graph, 2.0f)
- assertThrows<IllegalArgumentException> { graph.connect(outlet, sink.input) }
- }
-
- @Test
- fun testConnectInletBelongsToDifferentGraph() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graphA = engine.newGraph()
- val graphB = engine.newGraph()
-
- val sink = SimpleFlowSink(graphB, 2.0f)
- val source = SimpleFlowSource(graphA, 2000.0f, 0.8f)
-
- assertThrows<IllegalArgumentException> { graphA.connect(source.output, sink.input) }
- }
-
- @Test
- fun testConnectOutletBelongsToDifferentGraph() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graphA = engine.newGraph()
- val graphB = engine.newGraph()
-
- val sink = SimpleFlowSink(graphA, 2.0f)
- val source = SimpleFlowSource(graphB, 2000.0f, 0.8f)
-
- assertThrows<IllegalArgumentException> { graphA.connect(source.output, sink.input) }
- }
-
- @Test
- fun testConnectInletAlreadyConnected() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val sink = SimpleFlowSink(graph, 2.0f)
- val sourceA = SimpleFlowSource(graph, 2000.0f, 0.8f)
- val sourceB = SimpleFlowSource(graph, 2000.0f, 0.8f)
-
- graph.connect(sourceA.output, sink.input)
- assertThrows<IllegalStateException> { graph.connect(sourceB.output, sink.input) }
- }
-
- @Test
- fun testConnectOutletAlreadyConnected() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val sinkA = SimpleFlowSink(graph, 2.0f)
- val sinkB = SimpleFlowSink(graph, 2.0f)
- val source = SimpleFlowSource(graph, 2000.0f, 0.8f)
-
- graph.connect(source.output, sinkA.input)
- assertThrows<IllegalStateException> { graph.connect(source.output, sinkB.input) }
- }
-
- @Test
- fun testDisconnectInletInvalid() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val inlet = mockk<Inlet>()
- assertThrows<IllegalArgumentException> { graph.disconnect(inlet) }
- }
-
- @Test
- fun testDisconnectOutletInvalid() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val outlet = mockk<Outlet>()
- assertThrows<IllegalArgumentException> { graph.disconnect(outlet) }
- }
-
- @Test
- fun testDisconnectInletInvalidGraph() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graphA = engine.newGraph()
- val graphB = engine.newGraph()
-
- val sink = SimpleFlowSink(graphA, 2.0f)
-
- assertThrows<IllegalArgumentException> { graphB.disconnect(sink.input) }
- }
-
- @Test
- fun testDisconnectOutletInvalidGraph() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graphA = engine.newGraph()
- val graphB = engine.newGraph()
-
- val source = SimpleFlowSource(graphA, 2000.0f, 0.8f)
-
- assertThrows<IllegalArgumentException> { graphB.disconnect(source.output) }
- }
-
- @Test
- fun testInletEquality() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val sinkA = SimpleFlowSink(graph, 2.0f)
- val sinkB = SimpleFlowSink(graph, 2.0f)
-
- val multiplexer = MaxMinFlowMultiplexer(graph)
-
- assertEquals(sinkA.input, sinkA.input)
- assertNotEquals(sinkA.input, sinkB.input)
-
- assertNotEquals(multiplexer.newInput(), multiplexer.newInput())
- }
-
- @Test
- fun testOutletEquality() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val sourceA = SimpleFlowSource(graph, 2000.0f, 0.8f)
- val sourceB = SimpleFlowSource(graph, 2000.0f, 0.8f)
-
- val multiplexer = MaxMinFlowMultiplexer(graph)
-
- assertEquals(sourceA.output, sourceA.output)
- assertNotEquals(sourceA.output, sourceB.output)
-
- assertNotEquals(multiplexer.newOutput(), multiplexer.newOutput())
- }
-}
diff --git a/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/FlowTimerQueueTest.kt b/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/FlowTimerQueueTest.kt
deleted file mode 100644
index 059bd5f5..00000000
--- a/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/FlowTimerQueueTest.kt
+++ /dev/null
@@ -1,385 +0,0 @@
-/*
- * Copyright (c) 2022 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.flow2
-
-import io.mockk.mockk
-import org.junit.jupiter.api.Assertions.assertAll
-import org.junit.jupiter.api.Assertions.assertEquals
-import org.junit.jupiter.api.Assertions.assertNull
-import org.junit.jupiter.api.BeforeEach
-import org.junit.jupiter.api.Test
-
-/**
- * Test suite for the [FlowTimerQueue] class.
- */
-class FlowTimerQueueTest {
- private lateinit var queue: FlowTimerQueue
-
- @BeforeEach
- fun setUp() {
- queue = FlowTimerQueue(3)
- }
-
- /**
- * Test whether a call to [FlowTimerQueue.poll] returns `null` for an empty queue.
- */
- @Test
- fun testPollEmpty() {
- assertAll(
- { assertEquals(Long.MAX_VALUE, queue.peekDeadline()) },
- { assertNull(queue.poll(100L)) },
- )
- }
-
- /**
- * Test whether a call to [FlowTimerQueue.poll] returns the proper value for a queue with a single entry.
- */
- @Test
- fun testSingleEntry() {
- val entry = mockk<FlowStage>()
- entry.deadline = 100
- entry.timerIndex = -1
-
- queue.enqueue(entry)
-
- assertAll(
- { assertEquals(100, queue.peekDeadline()) },
- { assertNull(queue.poll(10L)) },
- { assertEquals(entry, queue.poll(200L)) },
- { assertNull(queue.poll(200L)) },
- )
- }
-
- /**
- * Test whether [FlowTimerQueue.poll] returns values in the queue in the proper order.
- */
- @Test
- fun testMultipleEntries() {
- val entryA = mockk<FlowStage>()
- entryA.deadline = 100
- entryA.timerIndex = -1
-
- queue.enqueue(entryA)
-
- val entryB = mockk<FlowStage>()
- entryB.deadline = 10
- entryB.timerIndex = -1
-
- queue.enqueue(entryB)
-
- val entryC = mockk<FlowStage>()
- entryC.deadline = 58
- entryC.timerIndex = -1
-
- queue.enqueue(entryC)
-
- assertAll(
- { assertEquals(10, queue.peekDeadline()) },
- { assertEquals(entryB, queue.poll(100L)) },
- { assertEquals(entryC, queue.poll(100L)) },
- { assertEquals(entryA, queue.poll(100L)) },
- { assertNull(queue.poll(100L)) },
- )
- }
-
- /**
- * Test that the queue is properly resized when the number of entries exceed the capacity.
- */
- @Test
- fun testResize() {
- val entryA = mockk<FlowStage>()
- entryA.deadline = 100
- entryA.timerIndex = -1
-
- queue.enqueue(entryA)
-
- val entryB = mockk<FlowStage>()
- entryB.deadline = 20
- entryB.timerIndex = -1
-
- queue.enqueue(entryB)
-
- val entryC = mockk<FlowStage>()
- entryC.deadline = 58
- entryC.timerIndex = -1
-
- queue.enqueue(entryC)
-
- val entryD = mockk<FlowStage>()
- entryD.deadline = 31
- entryD.timerIndex = -1
-
- queue.enqueue(entryD)
-
- assertAll(
- { assertEquals(20, queue.peekDeadline()) },
- { assertEquals(entryB, queue.poll(100L)) },
- { assertEquals(entryD, queue.poll(100L)) },
- { assertEquals(entryC, queue.poll(100L)) },
- { assertEquals(entryA, queue.poll(100L)) },
- { assertNull(queue.poll(100L)) },
- )
- }
-
- /**
- * Test to verify that we can change the deadline of the last element in the queue.
- */
- @Test
- fun testChangeDeadlineTail() {
- val entryA = mockk<FlowStage>()
- entryA.deadline = 100
- entryA.timerIndex = -1
-
- queue.enqueue(entryA)
-
- val entryB = mockk<FlowStage>()
- entryB.deadline = 20
- entryB.timerIndex = -1
-
- queue.enqueue(entryB)
-
- val entryC = mockk<FlowStage>()
- entryC.deadline = 58
- entryC.timerIndex = -1
-
- queue.enqueue(entryC)
-
- entryA.deadline = 10
- queue.enqueue(entryA)
-
- assertAll(
- { assertEquals(10, queue.peekDeadline()) },
- { assertEquals(entryA, queue.poll(100L)) },
- { assertEquals(entryB, queue.poll(100L)) },
- { assertEquals(entryC, queue.poll(100L)) },
- { assertNull(queue.poll(100L)) },
- )
- }
-
- /**
- * Test that we can change the deadline of the head entry in the queue.
- */
- @Test
- fun testChangeDeadlineMiddle() {
- val entryA = mockk<FlowStage>()
- entryA.deadline = 100
- entryA.timerIndex = -1
-
- queue.enqueue(entryA)
-
- val entryB = mockk<FlowStage>()
- entryB.deadline = 20
- entryB.timerIndex = -1
-
- queue.enqueue(entryB)
-
- val entryC = mockk<FlowStage>()
- entryC.deadline = 58
- entryC.timerIndex = -1
-
- queue.enqueue(entryC)
-
- entryC.deadline = 10
- queue.enqueue(entryC)
-
- assertAll(
- { assertEquals(10, queue.peekDeadline()) },
- { assertEquals(entryC, queue.poll(100L)) },
- { assertEquals(entryB, queue.poll(100L)) },
- { assertEquals(entryA, queue.poll(100L)) },
- { assertNull(queue.poll(100L)) },
- )
- }
-
- /**
- * Test that we can change the deadline of the head entry in the queue.
- */
- @Test
- fun testChangeDeadlineHead() {
- val entryA = mockk<FlowStage>()
- entryA.deadline = 100
- entryA.timerIndex = -1
-
- queue.enqueue(entryA)
-
- val entryB = mockk<FlowStage>()
- entryB.deadline = 20
- entryB.timerIndex = -1
-
- queue.enqueue(entryB)
-
- val entryC = mockk<FlowStage>()
- entryC.deadline = 58
- entryC.timerIndex = -1
-
- queue.enqueue(entryC)
-
- entryB.deadline = 30
- queue.enqueue(entryB)
-
- assertAll(
- { assertEquals(30, queue.peekDeadline()) },
- { assertEquals(entryB, queue.poll(100L)) },
- { assertEquals(entryC, queue.poll(100L)) },
- { assertEquals(entryA, queue.poll(100L)) },
- { assertNull(queue.poll(100L)) },
- )
- }
-
- /**
- * Test that an unchanged deadline results in a no-op.
- */
- @Test
- fun testChangeDeadlineNop() {
- val entryA = mockk<FlowStage>()
- entryA.deadline = 100
- entryA.timerIndex = -1
-
- queue.enqueue(entryA)
-
- val entryB = mockk<FlowStage>()
- entryB.deadline = 20
- entryB.timerIndex = -1
-
- queue.enqueue(entryB)
-
- val entryC = mockk<FlowStage>()
- entryC.deadline = 58
- entryC.timerIndex = -1
-
- queue.enqueue(entryC)
-
- // Should be a no-op
- queue.enqueue(entryA)
-
- assertAll(
- { assertEquals(20, queue.peekDeadline()) },
- { assertEquals(entryB, queue.poll(100L)) },
- { assertEquals(entryC, queue.poll(100L)) },
- { assertEquals(entryA, queue.poll(100L)) },
- { assertNull(queue.poll(100L)) },
- )
- }
-
- /**
- * Test that we can remove an entry from the end of the queue.
- */
- @Test
- fun testRemoveEntryTail() {
- val entryA = mockk<FlowStage>()
- entryA.deadline = 100
- entryA.timerIndex = -1
-
- queue.enqueue(entryA)
-
- val entryB = mockk<FlowStage>()
- entryB.deadline = 20
- entryB.timerIndex = -1
-
- queue.enqueue(entryB)
-
- val entryC = mockk<FlowStage>()
- entryC.deadline = 58
- entryC.timerIndex = -1
-
- queue.enqueue(entryC)
-
- entryC.deadline = Long.MAX_VALUE
- queue.enqueue(entryC)
-
- assertAll(
- { assertEquals(20, queue.peekDeadline()) },
- { assertEquals(entryB, queue.poll(100L)) },
- { assertEquals(entryA, queue.poll(100L)) },
- { assertNull(queue.poll(100L)) },
- )
- }
-
- /**
- * Test that we can remove an entry from the head of the queue.
- */
- @Test
- fun testRemoveEntryHead() {
- val entryA = mockk<FlowStage>()
- entryA.deadline = 100
- entryA.timerIndex = -1
-
- queue.enqueue(entryA)
-
- val entryB = mockk<FlowStage>()
- entryB.deadline = 20
- entryB.timerIndex = -1
-
- queue.enqueue(entryB)
-
- val entryC = mockk<FlowStage>()
- entryC.deadline = 58
- entryC.timerIndex = -1
-
- queue.enqueue(entryC)
-
- entryB.deadline = Long.MAX_VALUE
- queue.enqueue(entryB)
-
- assertAll(
- { assertEquals(58, queue.peekDeadline()) },
- { assertEquals(entryC, queue.poll(100L)) },
- { assertEquals(entryA, queue.poll(100L)) },
- { assertNull(queue.poll(100L)) },
- )
- }
-
- /**
- * Test that we can remove an entry from the middle of a queue.
- */
- @Test
- fun testRemoveEntryMiddle() {
- val entryA = mockk<FlowStage>()
- entryA.deadline = 100
- entryA.timerIndex = -1
-
- queue.enqueue(entryA)
-
- val entryB = mockk<FlowStage>()
- entryB.deadline = 20
- entryB.timerIndex = -1
-
- queue.enqueue(entryB)
-
- val entryC = mockk<FlowStage>()
- entryC.deadline = 58
- entryC.timerIndex = -1
-
- queue.enqueue(entryC)
-
- entryC.deadline = Long.MAX_VALUE
- queue.enqueue(entryC)
-
- assertAll(
- { assertEquals(20, queue.peekDeadline()) },
- { assertEquals(entryB, queue.poll(100L)) },
- { assertEquals(entryA, queue.poll(100L)) },
- { assertNull(queue.poll(100L)) },
- )
- }
-}
diff --git a/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/mux/ForwardingFlowMultiplexerTest.kt b/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/mux/ForwardingFlowMultiplexerTest.kt
deleted file mode 100644
index 2aef5174..00000000
--- a/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/mux/ForwardingFlowMultiplexerTest.kt
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright (c) 2022 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.flow2.mux
-
-import kotlinx.coroutines.yield
-import org.junit.jupiter.api.Assertions.assertEquals
-import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.assertAll
-import org.opendc.simulator.flow2.FlowEngine
-import org.opendc.simulator.flow2.sink.SimpleFlowSink
-import org.opendc.simulator.flow2.source.TraceFlowSource
-import org.opendc.simulator.kotlin.runSimulation
-
-/**
- * Test suite for the [ForwardingFlowMultiplexer] class.
- */
-class ForwardingFlowMultiplexerTest {
- /**
- * Test a trace workload.
- */
- @Test
- fun testTrace() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val switch = ForwardingFlowMultiplexer(graph)
- val sink = SimpleFlowSink(graph, 3200.0f)
- graph.connect(switch.newOutput(), sink.input)
-
- yield()
-
- assertEquals(sink.capacity, switch.capacity) { "Capacity is not detected" }
-
- val workload =
- TraceFlowSource(
- graph,
- TraceFlowSource.Trace(
- longArrayOf(1000, 2000, 3000, 4000),
- floatArrayOf(28.0f, 3500.0f, 0.0f, 183.0f),
- 4,
- ),
- )
- graph.connect(workload.output, switch.newInput())
-
- advanceUntilIdle()
-
- assertAll(
- { assertEquals(4000, timeSource.millis()) { "Took enough time" } },
- )
- }
-}
diff --git a/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/mux/MaxMinFlowMultiplexerTest.kt b/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/mux/MaxMinFlowMultiplexerTest.kt
deleted file mode 100644
index 0bcf4a3f..00000000
--- a/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/mux/MaxMinFlowMultiplexerTest.kt
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (c) 2022 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.flow2.mux
-
-import org.junit.jupiter.api.Assertions.assertEquals
-import org.junit.jupiter.api.Test
-import org.opendc.simulator.flow2.FlowEngine
-import org.opendc.simulator.flow2.sink.SimpleFlowSink
-import org.opendc.simulator.flow2.source.SimpleFlowSource
-import org.opendc.simulator.kotlin.runSimulation
-
-/**
- * Test suite for the [MaxMinFlowMultiplexer] class.
- */
-class MaxMinFlowMultiplexerTest {
- @Test
- fun testSmoke() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
- val switch = MaxMinFlowMultiplexer(graph)
-
- val sinks = List(2) { SimpleFlowSink(graph, 2000.0f) }
- for (source in sinks) {
- graph.connect(switch.newOutput(), source.input)
- }
-
- val source = SimpleFlowSource(graph, 2000.0f, 1.0f)
- graph.connect(source.output, switch.newInput())
-
- advanceUntilIdle()
-
- assertEquals(500, timeSource.millis())
- }
-}
diff --git a/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/sink/FlowSinkTest.kt b/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/sink/FlowSinkTest.kt
deleted file mode 100644
index 7085a4b9..00000000
--- a/opendc-simulator/opendc-simulator-flow/src/test/kotlin/org/opendc/simulator/flow2/sink/FlowSinkTest.kt
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (c) 2022 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.flow2.sink
-
-import kotlinx.coroutines.delay
-import org.junit.jupiter.api.Assertions.assertEquals
-import org.junit.jupiter.api.Test
-import org.opendc.simulator.flow2.FlowEngine
-import org.opendc.simulator.flow2.source.SimpleFlowSource
-import org.opendc.simulator.flow2.source.TraceFlowSource
-import org.opendc.simulator.kotlin.runSimulation
-import java.util.concurrent.ThreadLocalRandom
-
-/**
- * Test suite for the [SimpleFlowSink] class.
- */
-class FlowSinkTest {
- @Test
- fun testSmoke() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val sink = SimpleFlowSink(graph, 1.0f)
- val source = SimpleFlowSource(graph, 2.0f, 1.0f)
-
- graph.connect(source.output, sink.input)
- advanceUntilIdle()
-
- assertEquals(2000, timeSource.millis())
- }
-
- @Test
- fun testAdjustCapacity() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val sink = SimpleFlowSink(graph, 1.0f)
- val source = SimpleFlowSource(graph, 2.0f, 1.0f)
-
- graph.connect(source.output, sink.input)
-
- delay(1000)
- sink.capacity = 0.5f
-
- advanceUntilIdle()
-
- assertEquals(3000, timeSource.millis())
- }
-
- @Test
- fun testUtilization() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val sink = SimpleFlowSink(graph, 1.0f)
- val source = SimpleFlowSource(graph, 2.0f, 0.5f)
-
- graph.connect(source.output, sink.input)
- advanceUntilIdle()
-
- assertEquals(4000, timeSource.millis())
- }
-
- @Test
- fun testFragments() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
-
- val sink = SimpleFlowSink(graph, 1.0f)
- val trace =
- TraceFlowSource.Trace(
- longArrayOf(1000, 2000, 3000, 4000),
- floatArrayOf(1.0f, 0.5f, 2.0f, 1.0f),
- 4,
- )
- val source =
- TraceFlowSource(
- graph,
- trace,
- )
-
- graph.connect(source.output, sink.input)
- advanceUntilIdle()
-
- assertEquals(4000, timeSource.millis())
- }
-
- @Test
- fun benchmarkSink() {
- val random = ThreadLocalRandom.current()
- val traceSize = 10000000
- val trace =
- TraceFlowSource.Trace(
- LongArray(traceSize) { it * 1000L },
- FloatArray(traceSize) { random.nextDouble(0.0, 4500.0).toFloat() },
- traceSize,
- )
-
- return runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
- val sink = SimpleFlowSink(graph, 4200.0f)
- val source = TraceFlowSource(graph, trace)
- graph.connect(source.output, sink.input)
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-network/src/main/java/org/opendc/simulator/network/SimNetworkLink.java b/opendc-simulator/opendc-simulator-network/src/main/java/org/opendc/simulator/network/SimNetworkLink.java
deleted file mode 100644
index 1ea9cb0e..00000000
--- a/opendc-simulator/opendc-simulator-network/src/main/java/org/opendc/simulator/network/SimNetworkLink.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (c) 2022 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.network;
-
-/**
- * A physical bidirectional communication link between two [SimNetworkPort]s.
- */
-public final class SimNetworkLink {
- private final SimNetworkPort left;
- private final SimNetworkPort right;
-
- SimNetworkLink(SimNetworkPort left, SimNetworkPort right) {
- this.left = left;
- this.right = right;
- }
-
- /**
- * Determine whether the specified <code>port</code> participates in this network link.
- *
- * @return <code>true</code> if the port participates in this link, <code>false</code> otherwise.
- */
- public boolean contains(SimNetworkPort port) {
- return port == left || port == right;
- }
-
- /**
- * Obtain the opposite port to which the specified <code>port</code> is connected through this link.
- */
- public SimNetworkPort opposite(SimNetworkPort port) {
- if (port == left) {
- return right;
- } else if (port == right) {
- return left;
- }
-
- throw new IllegalArgumentException("Invalid port given");
- }
-
- /**
- * Return the first port of the link.
- */
- public SimNetworkPort getLeft() {
- return left;
- }
-
- /**
- * Return the second port of the link.
- */
- public SimNetworkPort getRight() {
- return right;
- }
-
- @Override
- public String toString() {
- return "SimNetworkLink[left=" + left + ",right=" + right + "]";
- }
-}
diff --git a/opendc-simulator/opendc-simulator-network/src/main/java/org/opendc/simulator/network/SimNetworkPort.java b/opendc-simulator/opendc-simulator-network/src/main/java/org/opendc/simulator/network/SimNetworkPort.java
deleted file mode 100644
index b5e09b9b..00000000
--- a/opendc-simulator/opendc-simulator-network/src/main/java/org/opendc/simulator/network/SimNetworkPort.java
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (c) 2022 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.network;
-
-import org.opendc.simulator.flow2.Inlet;
-import org.opendc.simulator.flow2.Outlet;
-
-/**
- * A network port allows network devices to be connected to network through links.
- */
-public abstract class SimNetworkPort {
- SimNetworkLink link;
-
- /**
- * Determine whether the network port is connected to another port.
- *
- * @return <code>true</code> if the network port is connected, <code>false</code> otherwise.
- */
- public boolean isConnected() {
- return link != null;
- }
-
- /**
- * Return network link which connects this port to another port.
- */
- public SimNetworkLink getLink() {
- return link;
- }
-
- /**
- * Connect this port to the specified <code>port</code>.
- */
- public void connect(SimNetworkPort port) {
- if (port == this) {
- throw new IllegalArgumentException("Circular reference");
- }
- if (isConnected()) {
- throw new IllegalStateException("Port already connected");
- }
- if (port.isConnected()) {
- throw new IllegalStateException("Target port already connected");
- }
-
- final SimNetworkLink link = new SimNetworkLink(this, port);
- this.link = link;
- port.link = link;
-
- // Start bidirectional flow channel between the two ports
- final Outlet outlet = getOutlet();
- final Inlet inlet = getInlet();
-
- outlet.getGraph().connect(outlet, port.getInlet());
- inlet.getGraph().connect(port.getOutlet(), inlet);
- }
-
- /**
- * Disconnect the current network link if it exists.
- */
- public void disconnect() {
- final SimNetworkLink link = this.link;
- if (link == null) {
- return;
- }
-
- final SimNetworkPort opposite = link.opposite(this);
- this.link = null;
- opposite.link = null;
-
- final Outlet outlet = getOutlet();
- final Inlet inlet = getInlet();
-
- outlet.getGraph().disconnect(outlet);
- inlet.getGraph().disconnect(inlet);
- }
-
- /**
- * Return the {@link Outlet} representing the outgoing traffic of this port.
- */
- protected abstract Outlet getOutlet();
-
- /**
- * An [Inlet] representing the ingoing traffic of this port.
- */
- protected abstract Inlet getInlet();
-
- @Override
- public String toString() {
- return "SimNetworkPort[isConnected=" + isConnected() + "]";
- }
-}
diff --git a/opendc-simulator/opendc-simulator-network/src/main/java/org/opendc/simulator/network/SimNetworkSink.java b/opendc-simulator/opendc-simulator-network/src/main/java/org/opendc/simulator/network/SimNetworkSink.java
deleted file mode 100644
index f8918328..00000000
--- a/opendc-simulator/opendc-simulator-network/src/main/java/org/opendc/simulator/network/SimNetworkSink.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (c) 2022 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.network;
-
-import org.opendc.simulator.flow2.FlowGraph;
-import org.opendc.simulator.flow2.Inlet;
-import org.opendc.simulator.flow2.Outlet;
-import org.opendc.simulator.flow2.sink.SimpleFlowSink;
-import org.opendc.simulator.flow2.source.EmptyFlowSource;
-
-/**
- * A network sink which discards all received traffic and does not generate any traffic itself.
- */
-public final class SimNetworkSink extends SimNetworkPort {
- private final EmptyFlowSource source;
- private final SimpleFlowSink sink;
-
- /**
- * Construct a {@link SimNetworkSink} instance.
- *
- * @param graph The {@link FlowGraph} to which the sink belongs.
- * @param capacity The capacity of the sink in terms of processed data.
- */
- public SimNetworkSink(FlowGraph graph, float capacity) {
- this.source = new EmptyFlowSource(graph);
- this.sink = new SimpleFlowSink(graph, capacity);
- }
-
- /**
- * Return the capacity of the sink.
- */
- public float getCapacity() {
- return sink.getCapacity();
- }
-
- @Override
- protected Outlet getOutlet() {
- return source.getOutput();
- }
-
- @Override
- protected Inlet getInlet() {
- return sink.getInput();
- }
-
- @Override
- public String toString() {
- return "SimNetworkSink[capacity=" + getCapacity() + "]";
- }
-}
diff --git a/opendc-simulator/opendc-simulator-network/src/main/java/org/opendc/simulator/network/SimNetworkSwitch.java b/opendc-simulator/opendc-simulator-network/src/main/java/org/opendc/simulator/network/SimNetworkSwitch.java
deleted file mode 100644
index b05dc53d..00000000
--- a/opendc-simulator/opendc-simulator-network/src/main/java/org/opendc/simulator/network/SimNetworkSwitch.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2022 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.network;
-
-import java.util.List;
-
-/**
- * A network device connects devices on a network by switching the traffic over its ports.
- */
-public interface SimNetworkSwitch {
- /**
- * Return the ports of the switch.
- */
- List<SimNetworkPort> getPorts();
-}
diff --git a/opendc-simulator/opendc-simulator-network/src/main/java/org/opendc/simulator/network/SimNetworkSwitchVirtual.java b/opendc-simulator/opendc-simulator-network/src/main/java/org/opendc/simulator/network/SimNetworkSwitchVirtual.java
deleted file mode 100644
index a94bf799..00000000
--- a/opendc-simulator/opendc-simulator-network/src/main/java/org/opendc/simulator/network/SimNetworkSwitchVirtual.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (c) 2022 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.network;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import org.opendc.simulator.flow2.FlowGraph;
-import org.opendc.simulator.flow2.Inlet;
-import org.opendc.simulator.flow2.Outlet;
-import org.opendc.simulator.flow2.mux.FlowMultiplexer;
-import org.opendc.simulator.flow2.mux.MaxMinFlowMultiplexer;
-
-/**
- * A {@link SimNetworkSwitch} that can support new networking ports on demand.
- */
-public final class SimNetworkSwitchVirtual implements SimNetworkSwitch {
- private final List<Port> ports = new ArrayList<>();
-
- /**
- * The {@link MaxMinFlowMultiplexer} to actually perform the switching.
- */
- private final MaxMinFlowMultiplexer mux;
-
- /**
- * Construct a {@link SimNetworkSwitchVirtual} instance.
- *
- * @param graph The {@link FlowGraph} to drive the simulation.
- */
- public SimNetworkSwitchVirtual(FlowGraph graph) {
- this.mux = new MaxMinFlowMultiplexer(graph);
- }
-
- /**
- * Open a new port on the switch.
- */
- public Port newPort() {
- final Port port = new Port(mux);
- ports.add(port);
- return port;
- }
-
- @Override
- public List<SimNetworkPort> getPorts() {
- return Collections.unmodifiableList(ports);
- }
-
- /**
- * A port on the network switch.
- */
- public class Port extends SimNetworkPort implements AutoCloseable {
- private final FlowMultiplexer mux;
- private final Inlet inlet;
- private final Outlet outlet;
- private boolean isClosed;
-
- private Port(FlowMultiplexer mux) {
- this.mux = mux;
- this.inlet = mux.newInput();
- this.outlet = mux.newOutput();
- }
-
- @Override
- protected Outlet getOutlet() {
- if (isClosed) {
- throw new IllegalStateException("Port is closed");
- }
- return outlet;
- }
-
- @Override
- protected Inlet getInlet() {
- if (isClosed) {
- throw new IllegalStateException("Port is closed");
- }
- return inlet;
- }
-
- @Override
- public void close() {
- isClosed = true;
- mux.releaseInput(inlet);
- mux.releaseOutput(outlet);
- ports.remove(this);
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-network/src/test/kotlin/org/opendc/simulator/network/SimNetworkLinkTest.kt b/opendc-simulator/opendc-simulator-network/src/test/kotlin/org/opendc/simulator/network/SimNetworkLinkTest.kt
deleted file mode 100644
index 9863507d..00000000
--- a/opendc-simulator/opendc-simulator-network/src/test/kotlin/org/opendc/simulator/network/SimNetworkLinkTest.kt
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (c) 2021 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.network
-
-import io.mockk.mockk
-import org.junit.jupiter.api.Assertions.assertEquals
-import org.junit.jupiter.api.Assertions.assertFalse
-import org.junit.jupiter.api.Assertions.assertTrue
-import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.assertThrows
-
-/**
- * Test suite for [SimNetworkLink] class.
- */
-class SimNetworkLinkTest {
- @Test
- fun testContainsLeft() {
- val left = mockk<SimNetworkPort>()
- val right = mockk<SimNetworkPort>()
-
- val link = SimNetworkLink(left, right)
- assertTrue(left in link)
- }
-
- @Test
- fun testContainsRight() {
- val left = mockk<SimNetworkPort>()
- val right = mockk<SimNetworkPort>()
-
- val link = SimNetworkLink(left, right)
- assertTrue(right in link)
- }
-
- @Test
- fun testContainsNone() {
- val left = mockk<SimNetworkPort>()
- val right = mockk<SimNetworkPort>()
- val none = mockk<SimNetworkPort>()
-
- val link = SimNetworkLink(left, right)
- assertFalse(none in link)
- }
-
- @Test
- fun testOppositeLeft() {
- val left = mockk<SimNetworkPort>()
- val right = mockk<SimNetworkPort>()
-
- val link = SimNetworkLink(left, right)
- assertEquals(right, link.opposite(left))
- }
-
- @Test
- fun testOppositeRight() {
- val left = mockk<SimNetworkPort>()
- val right = mockk<SimNetworkPort>()
-
- val link = SimNetworkLink(left, right)
- assertEquals(left, link.opposite(right))
- }
-
- @Test
- fun testOppositeNone() {
- val left = mockk<SimNetworkPort>()
- val right = mockk<SimNetworkPort>()
- val none = mockk<SimNetworkPort>()
-
- val link = SimNetworkLink(left, right)
- assertThrows<IllegalArgumentException> { link.opposite(none) }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-network/src/test/kotlin/org/opendc/simulator/network/SimNetworkSinkTest.kt b/opendc-simulator/opendc-simulator-network/src/test/kotlin/org/opendc/simulator/network/SimNetworkSinkTest.kt
deleted file mode 100644
index 4655bfea..00000000
--- a/opendc-simulator/opendc-simulator-network/src/test/kotlin/org/opendc/simulator/network/SimNetworkSinkTest.kt
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (c) 2021 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.network
-
-import io.mockk.every
-import io.mockk.mockk
-import io.mockk.verify
-import kotlinx.coroutines.yield
-import org.junit.jupiter.api.Assertions.assertAll
-import org.junit.jupiter.api.Assertions.assertEquals
-import org.junit.jupiter.api.Assertions.assertFalse
-import org.junit.jupiter.api.Assertions.assertNull
-import org.junit.jupiter.api.Assertions.assertTrue
-import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.assertDoesNotThrow
-import org.junit.jupiter.api.assertThrows
-import org.opendc.simulator.flow2.FlowEngine
-import org.opendc.simulator.kotlin.runSimulation
-
-/**
- * Test suite for the [SimNetworkSink] class.
- */
-class SimNetworkSinkTest {
- @Test
- fun testInitialState() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
- val sink = SimNetworkSink(graph, 100.0f)
-
- assertAll(
- { assertFalse(sink.isConnected) },
- { assertNull(sink.link) },
- { assertEquals(100.0f, sink.capacity) },
- )
- }
-
- @Test
- fun testDisconnectIdempotent() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
- val sink = SimNetworkSink(graph, 100.0f)
-
- assertDoesNotThrow { sink.disconnect() }
- assertFalse(sink.isConnected)
- }
-
- @Test
- fun testConnectCircular() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
- val sink = SimNetworkSink(graph, 100.0f)
-
- assertThrows<IllegalArgumentException> {
- sink.connect(sink)
- }
- }
-
- @Test
- fun testConnectAlreadyConnectedTarget() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
- val sink = SimNetworkSink(graph, 100.0f)
- val source = mockk<SimNetworkPort>(relaxUnitFun = true)
- every { source.isConnected } returns true
-
- assertThrows<IllegalStateException> {
- sink.connect(source)
- }
- }
-
- @Test
- fun testConnectAlreadyConnected() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
- val sink = SimNetworkSink(graph, 100.0f)
- val source1 = TestSource(graph)
-
- val source2 = mockk<SimNetworkPort>(relaxUnitFun = true)
-
- every { source2.isConnected } returns false
-
- sink.connect(source1)
- assertThrows<IllegalStateException> {
- sink.connect(source2)
- }
- }
-
- @Test
- fun testConnect() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
- val sink = SimNetworkSink(graph, 100.0f)
- val source = TestSource(graph)
-
- sink.connect(source)
-
- yield()
-
- assertAll(
- { assertTrue(sink.isConnected) },
- { assertTrue(source.isConnected) },
- { assertEquals(100.0f, source.outlet.capacity) },
- )
-
- verify { source.logic.onUpdate(any(), any()) }
- }
-
- @Test
- fun testDisconnect() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
- val sink = SimNetworkSink(graph, 100.0f)
- val source = TestSource(graph)
-
- sink.connect(source)
- sink.disconnect()
-
- yield()
-
- assertAll(
- { assertFalse(sink.isConnected) },
- { assertFalse(source.isConnected) },
- { assertEquals(0.0f, source.outlet.capacity) },
- )
- }
-}
diff --git a/opendc-simulator/opendc-simulator-network/src/test/kotlin/org/opendc/simulator/network/SimNetworkSwitchVirtualTest.kt b/opendc-simulator/opendc-simulator-network/src/test/kotlin/org/opendc/simulator/network/SimNetworkSwitchVirtualTest.kt
deleted file mode 100644
index b5a00ffc..00000000
--- a/opendc-simulator/opendc-simulator-network/src/test/kotlin/org/opendc/simulator/network/SimNetworkSwitchVirtualTest.kt
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (c) 2021 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.network
-
-import io.mockk.verify
-import kotlinx.coroutines.yield
-import org.junit.jupiter.api.Assertions.assertAll
-import org.junit.jupiter.api.Assertions.assertEquals
-import org.junit.jupiter.api.Assertions.assertTrue
-import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.assertThrows
-import org.opendc.simulator.flow2.FlowEngine
-import org.opendc.simulator.kotlin.runSimulation
-
-/**
- * Test suite for the [SimNetworkSwitchVirtual] class.
- */
-class SimNetworkSwitchVirtualTest {
- @Test
- fun testConnect() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
- val sink = SimNetworkSink(graph, 100.0f)
- val source = TestSource(graph)
- val switch = SimNetworkSwitchVirtual(graph)
-
- switch.newPort().connect(sink)
- switch.newPort().connect(source)
-
- yield()
-
- assertAll(
- { assertTrue(sink.isConnected) },
- { assertTrue(source.isConnected) },
- { assertEquals(100.0f, source.outlet.capacity) },
- )
-
- verify { source.logic.onUpdate(any(), any()) }
- }
-
- @Test
- fun testConnectClosedPort() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
- val sink = SimNetworkSink(graph, 100.0f)
- val switch = SimNetworkSwitchVirtual(graph)
-
- val port = switch.newPort()
- port.close()
-
- assertThrows<IllegalStateException> {
- port.connect(sink)
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-network/src/test/kotlin/org/opendc/simulator/network/TestSource.kt b/opendc-simulator/opendc-simulator-network/src/test/kotlin/org/opendc/simulator/network/TestSource.kt
deleted file mode 100644
index 298a5d48..00000000
--- a/opendc-simulator/opendc-simulator-network/src/test/kotlin/org/opendc/simulator/network/TestSource.kt
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (c) 2022 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.network
-
-import io.mockk.spyk
-import org.opendc.simulator.flow2.FlowGraph
-import org.opendc.simulator.flow2.FlowStage
-import org.opendc.simulator.flow2.FlowStageLogic
-import org.opendc.simulator.flow2.InPort
-import org.opendc.simulator.flow2.Inlet
-import org.opendc.simulator.flow2.OutPort
-import org.opendc.simulator.flow2.Outlet
-
-/**
- * A [SimNetworkPort] that acts as a test source.
- */
-class TestSource(graph: FlowGraph) : SimNetworkPort(), FlowStageLogic {
- val logic = spyk(this)
- private val stage = graph.newStage(logic)
-
- val outlet: OutPort = stage.getOutlet("out")
- val inlet: InPort = stage.getInlet("in")
-
- init {
- outlet.push(80.0f)
- }
-
- override fun onUpdate(
- ctx: FlowStage,
- now: Long,
- ): Long = Long.MAX_VALUE
-
- override fun getOutlet(): Outlet = outlet
-
- override fun getInlet(): Inlet = inlet
-}
diff --git a/opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimPdu.java b/opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimPdu.java
deleted file mode 100644
index 8790a2d7..00000000
--- a/opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimPdu.java
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright (c) 2022 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.power;
-
-import org.jetbrains.annotations.NotNull;
-import org.opendc.simulator.flow2.FlowGraph;
-import org.opendc.simulator.flow2.Inlet;
-import org.opendc.simulator.flow2.Outlet;
-import org.opendc.simulator.flow2.mux.FlowMultiplexer;
-import org.opendc.simulator.flow2.mux.MaxMinFlowMultiplexer;
-import org.opendc.simulator.flow2.util.FlowTransform;
-import org.opendc.simulator.flow2.util.FlowTransformer;
-
-/**
- * A model of a Power Distribution Unit (PDU).
- */
-public final class SimPdu extends SimPowerInlet {
- /**
- * The {@link FlowMultiplexer} that distributes the electricity over the PDU outlets.
- */
- private final MaxMinFlowMultiplexer mux;
-
- /**
- * A {@link FlowTransformer} that applies the power loss to the PDU's power inlet.
- */
- private final FlowTransformer transformer;
-
- /**
- * Construct a {@link SimPdu} instance.
- *
- * @param graph The underlying {@link FlowGraph} to which the PDU belongs.
- * @param idlePower The idle power consumption of the PDU independent of the load on the PDU.
- * @param lossCoefficient The coefficient for the power loss of the PDU proportional to the square load.
- */
- public SimPdu(FlowGraph graph, float idlePower, float lossCoefficient) {
- this.mux = new MaxMinFlowMultiplexer(graph);
- this.transformer = new FlowTransformer(graph, new FlowTransform() {
- @Override
- public float apply(float value) {
- // See https://download.schneider-electric.com/files?p_Doc_Ref=SPD_NRAN-66CK3D_EN
- return value * (lossCoefficient * value + 1) + idlePower;
- }
-
- @Override
- public float applyInverse(float value) {
- float c = lossCoefficient;
- if (c != 0.f) {
- return (float) (1 + Math.sqrt(4 * value * c - 4 * idlePower * c + 1)) / (2 * c);
- } else {
- return value - idlePower;
- }
- }
- });
-
- graph.connect(mux.newOutput(), transformer.getInput());
- }
-
- /**
- * Construct a {@link SimPdu} instance without any loss.
- *
- * @param graph The underlying {@link FlowGraph} to which the PDU belongs.
- */
- public SimPdu(FlowGraph graph) {
- this(graph, 0.f, 0.f);
- }
-
- /**
- * Create a new PDU outlet.
- */
- public PowerOutlet newOutlet() {
- return new PowerOutlet(mux);
- }
-
- @NotNull
- @Override
- public Outlet getFlowOutlet() {
- return transformer.getOutput();
- }
-
- @Override
- public String toString() {
- return "SimPdu";
- }
-
- /**
- * A PDU outlet.
- */
- public static final class PowerOutlet extends SimPowerOutlet implements AutoCloseable {
- private final FlowMultiplexer mux;
- private final Inlet inlet;
- private boolean isClosed;
-
- private PowerOutlet(FlowMultiplexer mux) {
- this.mux = mux;
- this.inlet = mux.newInput();
- }
-
- /**
- * Remove the outlet from the PDU.
- */
- @Override
- public void close() {
- isClosed = true;
- mux.releaseInput(inlet);
- }
-
- @Override
- public String toString() {
- return "SimPdu.Outlet";
- }
-
- @NotNull
- @Override
- protected Inlet getFlowInlet() {
- if (isClosed) {
- throw new IllegalStateException("Outlet is closed");
- }
- return inlet;
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimPowerInlet.java b/opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimPowerInlet.java
deleted file mode 100644
index a6e167c2..00000000
--- a/opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimPowerInlet.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (c) 2022 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.power;
-
-import org.opendc.simulator.flow2.Outlet;
-
-/**
- * An abstract inlet that consumes electricity from a power outlet.
- */
-public abstract class SimPowerInlet {
- SimPowerOutlet outlet;
-
- /**
- * Determine whether the inlet is connected to a {@link SimPowerOutlet}.
- *
- * @return <code>true</code> if the inlet is connected to an outlet, <code>false</code> otherwise.
- */
- public boolean isConnected() {
- return outlet != null;
- }
-
- /**
- * Return the {@link SimPowerOutlet} to which the inlet is connected.
- */
- public SimPowerOutlet getOutlet() {
- return outlet;
- }
-
- /**
- * Return the flow {@link Outlet} that models the consumption of a power inlet as flow output.
- */
- protected abstract Outlet getFlowOutlet();
-}
diff --git a/opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimPowerOutlet.java b/opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimPowerOutlet.java
deleted file mode 100644
index e33d35d0..00000000
--- a/opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimPowerOutlet.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright (c) 2022 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.power;
-
-import org.opendc.simulator.flow2.Inlet;
-import org.opendc.simulator.flow2.Outlet;
-
-/**
- * An abstract outlet that provides a source of electricity for datacenter components.
- */
-public abstract class SimPowerOutlet {
- private SimPowerInlet inlet;
-
- /**
- * Determine whether the outlet is connected to a {@link SimPowerInlet}.
- *
- * @return <code>true</code> if the outlet is connected to an inlet, <code>false</code> otherwise.
- */
- public boolean isConnected() {
- return inlet != null;
- }
-
- /**
- * Return the {@link SimPowerInlet} to which the outlet is connected.
- */
- public SimPowerInlet getInlet() {
- return inlet;
- }
-
- /**
- * Connect the specified power [inlet] to this outlet.
- *
- * @param inlet The inlet to connect to the outlet.
- */
- public void connect(SimPowerInlet inlet) {
- if (isConnected()) {
- throw new IllegalStateException("Outlet already connected");
- }
- if (inlet.isConnected()) {
- throw new IllegalStateException("Inlet already connected");
- }
-
- this.inlet = inlet;
- this.inlet.outlet = this;
-
- final Inlet flowInlet = getFlowInlet();
- final Outlet flowOutlet = inlet.getFlowOutlet();
-
- flowInlet.getGraph().connect(flowOutlet, flowInlet);
- }
-
- /**
- * Disconnect the connected power outlet from this inlet
- */
- public void disconnect() {
- SimPowerInlet inlet = this.inlet;
- if (inlet != null) {
- this.inlet = null;
- assert inlet.outlet == this : "Inlet state incorrect";
- inlet.outlet = null;
-
- final Inlet flowInlet = getFlowInlet();
- flowInlet.getGraph().disconnect(flowInlet);
- }
- }
-
- /**
- * Return the flow {@link Inlet} that models the consumption of a power outlet as flow input.
- */
- protected abstract Inlet getFlowInlet();
-}
diff --git a/opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimPowerSource.java b/opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimPowerSource.java
deleted file mode 100644
index a2d62c48..00000000
--- a/opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimPowerSource.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (c) 2022 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.power;
-
-import org.opendc.simulator.flow2.FlowGraph;
-import org.opendc.simulator.flow2.Inlet;
-import org.opendc.simulator.flow2.sink.SimpleFlowSink;
-
-/**
- * A {@link SimPowerOutlet} that represents a source of electricity with a maximum capacity.
- */
-public final class SimPowerSource extends SimPowerOutlet {
- /**
- * The resource source that drives this power source.
- */
- private final SimpleFlowSink sink;
-
- /**
- * Construct a {@link SimPowerSource} instance.
- *
- * @param graph The underlying {@link FlowGraph} to which the power source belongs.
- * @param capacity The maximum amount of power provided by the source.
- */
- public SimPowerSource(FlowGraph graph, float capacity) {
- this.sink = new SimpleFlowSink(graph, capacity);
- }
-
- /**
- * Return the capacity of the power source.
- */
- public float getCapacity() {
- return sink.getCapacity();
- }
-
- /**
- * Return the power draw at this instant.
- */
- public float getPowerDraw() {
- return sink.getRate();
- }
-
- @Override
- protected Inlet getFlowInlet() {
- return sink.getInput();
- }
-
- @Override
- public String toString() {
- return "SimPowerSource";
- }
-}
diff --git a/opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimUps.java b/opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimUps.java
deleted file mode 100644
index df7508d9..00000000
--- a/opendc-simulator/opendc-simulator-power/src/main/java/org/opendc/simulator/power/SimUps.java
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright (c) 2022 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.power;
-
-import org.jetbrains.annotations.NotNull;
-import org.opendc.simulator.flow2.FlowGraph;
-import org.opendc.simulator.flow2.Inlet;
-import org.opendc.simulator.flow2.Outlet;
-import org.opendc.simulator.flow2.mux.FlowMultiplexer;
-import org.opendc.simulator.flow2.mux.MaxMinFlowMultiplexer;
-import org.opendc.simulator.flow2.util.FlowTransform;
-import org.opendc.simulator.flow2.util.FlowTransformer;
-
-/**
- * A model of an Uninterruptible Power Supply (UPS).
- * <p>
- * This model aggregates multiple power sources into a single source in order to ensure that power is always available.
- */
-public final class SimUps extends SimPowerOutlet {
- /**
- * The {@link FlowMultiplexer} that distributes the electricity over the PDU outlets.
- */
- private final MaxMinFlowMultiplexer mux;
-
- /**
- * A {@link FlowTransformer} that applies the power loss to the PDU's power inlet.
- */
- private final FlowTransformer transformer;
-
- /**
- * Construct a {@link SimUps} instance.
- *
- * @param graph The underlying {@link FlowGraph} to which the UPS belongs.
- * @param idlePower The idle power consumption of the UPS independent of the load.
- * @param lossCoefficient The coefficient for the power loss of the UPS proportional to the load.
- */
- public SimUps(FlowGraph graph, float idlePower, float lossCoefficient) {
- this.mux = new MaxMinFlowMultiplexer(graph);
- this.transformer = new FlowTransformer(graph, new FlowTransform() {
- @Override
- public float apply(float value) {
- // See https://download.schneider-electric.com/files?p_Doc_Ref=SPD_NRAN-66CK3D_EN
- return value * (lossCoefficient + 1) + idlePower;
- }
-
- @Override
- public float applyInverse(float value) {
- return (value - idlePower) / (lossCoefficient + 1);
- }
- });
-
- graph.connect(transformer.getOutput(), mux.newInput());
- }
-
- /**
- * Construct a {@link SimUps} instance without any loss.
- *
- * @param graph The underlying {@link FlowGraph} to which the UPS belongs.
- */
- public SimUps(FlowGraph graph) {
- this(graph, 0.f, 0.f);
- }
-
- /**
- * Create a new UPS inlet.
- */
- public PowerInlet newInlet() {
- return new PowerInlet(mux);
- }
-
- @Override
- protected Inlet getFlowInlet() {
- return transformer.getInput();
- }
-
- @Override
- public String toString() {
- return "SimUps";
- }
-
- /**
- * A UPS inlet.
- */
- public static final class PowerInlet extends SimPowerInlet implements AutoCloseable {
- private final FlowMultiplexer mux;
- private final Outlet outlet;
- private boolean isClosed;
-
- private PowerInlet(FlowMultiplexer mux) {
- this.mux = mux;
- this.outlet = mux.newOutput();
- }
-
- /**
- * Remove the inlet from the PDU.
- */
- @Override
- public void close() {
- isClosed = true;
- mux.releaseOutput(outlet);
- }
-
- @Override
- public String toString() {
- return "SimPdu.Inlet";
- }
-
- @NotNull
- @Override
- protected Outlet getFlowOutlet() {
- if (isClosed) {
- throw new IllegalStateException("Inlet is closed");
- }
- return outlet;
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-power/src/test/kotlin/org/opendc/simulator/power/SimPduTest.kt b/opendc-simulator/opendc-simulator-power/src/test/kotlin/org/opendc/simulator/power/SimPduTest.kt
deleted file mode 100644
index 9df72c49..00000000
--- a/opendc-simulator/opendc-simulator-power/src/test/kotlin/org/opendc/simulator/power/SimPduTest.kt
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright (c) 2021 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.power
-
-import kotlinx.coroutines.yield
-import org.junit.jupiter.api.Assertions.assertEquals
-import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.assertThrows
-import org.opendc.simulator.flow2.FlowEngine
-import org.opendc.simulator.kotlin.runSimulation
-
-/**
- * Test suite for the [SimPdu] class.
- */
-internal class SimPduTest {
- @Test
- fun testZeroOutlets() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
- val source = SimPowerSource(graph, 100.0f)
- val pdu = SimPdu(graph)
- source.connect(pdu)
-
- yield()
-
- assertEquals(0.0f, source.powerDraw)
- }
-
- @Test
- fun testSingleOutlet() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
- val source = SimPowerSource(graph, 100.0f)
- val pdu = SimPdu(graph)
- source.connect(pdu)
- pdu.newOutlet().connect(TestInlet(graph))
-
- yield()
-
- assertEquals(100.0f, source.powerDraw)
- }
-
- @Test
- fun testDoubleOutlet() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
- val source = SimPowerSource(graph, 200.0f)
- val pdu = SimPdu(graph)
- source.connect(pdu)
-
- pdu.newOutlet().connect(TestInlet(graph))
- pdu.newOutlet().connect(TestInlet(graph))
-
- yield()
-
- assertEquals(200.0f, source.powerDraw)
- }
-
- @Test
- fun testDisconnect() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
- val source = SimPowerSource(graph, 300.0f)
- val pdu = SimPdu(graph)
- source.connect(pdu)
-
- val outlet = pdu.newOutlet()
- outlet.connect(TestInlet(graph))
- outlet.disconnect()
-
- yield()
-
- assertEquals(0.0f, source.powerDraw)
- }
-
- @Test
- fun testLoss() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
- val source = SimPowerSource(graph, 500.0f)
- // https://download.schneider-electric.com/files?p_Doc_Ref=SPD_NRAN-66CK3D_EN
- val pdu = SimPdu(graph, 1.5f, 0.015f)
- source.connect(pdu)
- pdu.newOutlet().connect(TestInlet(graph))
-
- yield()
-
- assertEquals(251.5f, source.powerDraw, 0.01f)
- }
-
- @Test
- fun testOutletClose() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
- val source = SimPowerSource(graph, 100.0f)
- val pdu = SimPdu(graph)
- source.connect(pdu)
- val outlet = pdu.newOutlet()
- outlet.close()
-
- yield()
-
- assertThrows<IllegalStateException> {
- outlet.connect(TestInlet(graph))
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-power/src/test/kotlin/org/opendc/simulator/power/SimPowerSourceTest.kt b/opendc-simulator/opendc-simulator-power/src/test/kotlin/org/opendc/simulator/power/SimPowerSourceTest.kt
deleted file mode 100644
index bbc9ad92..00000000
--- a/opendc-simulator/opendc-simulator-power/src/test/kotlin/org/opendc/simulator/power/SimPowerSourceTest.kt
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (c) 2021 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.power
-
-import io.mockk.every
-import io.mockk.mockk
-import kotlinx.coroutines.yield
-import org.junit.jupiter.api.Assertions.assertAll
-import org.junit.jupiter.api.Assertions.assertEquals
-import org.junit.jupiter.api.Assertions.assertFalse
-import org.junit.jupiter.api.Assertions.assertNull
-import org.junit.jupiter.api.Assertions.assertTrue
-import org.junit.jupiter.api.Test
-import org.junit.jupiter.api.assertDoesNotThrow
-import org.junit.jupiter.api.assertThrows
-import org.opendc.simulator.flow2.FlowEngine
-import org.opendc.simulator.kotlin.runSimulation
-
-/**
- * Test suite for the [SimPowerSource]
- */
-internal class SimPowerSourceTest {
- @Test
- fun testInitialState() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
- val source = SimPowerSource(graph, 100.0f)
-
- yield()
-
- assertAll(
- { assertFalse(source.isConnected) },
- { assertNull(source.inlet) },
- { assertEquals(100.0f, source.capacity) },
- )
- }
-
- @Test
- fun testDisconnectIdempotent() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
- val source = SimPowerSource(graph, 100.0f)
-
- assertDoesNotThrow { source.disconnect() }
- assertFalse(source.isConnected)
- }
-
- @Test
- fun testConnect() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
- val source = SimPowerSource(graph, 100.0f)
- val inlet = TestInlet(graph)
-
- source.connect(inlet)
-
- yield()
-
- assertAll(
- { assertTrue(source.isConnected) },
- { assertEquals(inlet, source.inlet) },
- { assertTrue(inlet.isConnected) },
- { assertEquals(source, inlet.outlet) },
- { assertEquals(100.0f, source.powerDraw) },
- )
- }
-
- @Test
- fun testDisconnect() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
- val source = SimPowerSource(graph, 100.0f)
- val inlet = TestInlet(graph)
-
- source.connect(inlet)
- source.disconnect()
-
- yield()
-
- assertEquals(0.0f, inlet.flowOutlet.capacity)
- }
-
- @Test
- fun testDisconnectAssertion() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
- val source = SimPowerSource(graph, 100.0f)
-
- val inlet = mockk<SimPowerInlet>(relaxUnitFun = true)
- every { inlet.isConnected } returns false
- every { inlet.flowOutlet } returns TestInlet(graph).flowOutlet
-
- source.connect(inlet)
- inlet.outlet = null
-
- assertThrows<AssertionError> {
- source.disconnect()
- }
- }
-
- @Test
- fun testOutletAlreadyConnected() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
- val source = SimPowerSource(graph, 100.0f)
- val inlet = TestInlet(graph)
-
- source.connect(inlet)
- assertThrows<IllegalStateException> {
- source.connect(TestInlet(graph))
- }
-
- assertEquals(inlet, source.inlet)
- }
-
- @Test
- fun testInletAlreadyConnected() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
- val source = SimPowerSource(graph, 100.0f)
- val inlet = mockk<SimPowerInlet>(relaxUnitFun = true)
- every { inlet.isConnected } returns true
-
- assertThrows<IllegalStateException> {
- source.connect(inlet)
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-power/src/test/kotlin/org/opendc/simulator/power/SimUpsTest.kt b/opendc-simulator/opendc-simulator-power/src/test/kotlin/org/opendc/simulator/power/SimUpsTest.kt
deleted file mode 100644
index cbd23887..00000000
--- a/opendc-simulator/opendc-simulator-power/src/test/kotlin/org/opendc/simulator/power/SimUpsTest.kt
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (c) 2021 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.power
-
-import kotlinx.coroutines.yield
-import org.junit.jupiter.api.Assertions.assertAll
-import org.junit.jupiter.api.Assertions.assertEquals
-import org.junit.jupiter.api.Test
-import org.opendc.simulator.flow2.FlowEngine
-import org.opendc.simulator.kotlin.runSimulation
-
-/**
- * Test suite for the [SimUps] class.
- */
-internal class SimUpsTest {
- @Test
- fun testSingleInlet() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
- val source = SimPowerSource(graph, 200.0f)
- val ups = SimUps(graph)
- source.connect(ups.newInlet())
- ups.connect(TestInlet(graph))
-
- yield()
-
- assertEquals(100.0f, source.powerDraw)
- }
-
- @Test
- fun testDoubleInlet() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
- val source1 = SimPowerSource(graph, 200.0f)
- val source2 = SimPowerSource(graph, 200.0f)
- val ups = SimUps(graph)
- source1.connect(ups.newInlet())
- source2.connect(ups.newInlet())
-
- ups.connect(TestInlet(graph))
-
- yield()
-
- assertAll(
- { assertEquals(50.0f, source1.powerDraw) },
- { assertEquals(50.0f, source2.powerDraw) },
- )
- }
-
- @Test
- fun testLoss() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
- val source = SimPowerSource(graph, 500.0f)
- // https://download.schneider-electric.com/files?p_Doc_Ref=SPD_NRAN-66CK3D_EN
- val ups = SimUps(graph, 4.0f, 0.05f)
- source.connect(ups.newInlet())
- ups.connect(TestInlet(graph))
-
- yield()
-
- assertEquals(109.0f, source.powerDraw, 0.01f)
- }
-
- @Test
- fun testDisconnect() =
- runSimulation {
- val engine = FlowEngine.create(dispatcher)
- val graph = engine.newGraph()
- val source1 = SimPowerSource(graph, 200.0f)
- val source2 = SimPowerSource(graph, 200.0f)
- val ups = SimUps(graph)
- source1.connect(ups.newInlet())
- source2.connect(ups.newInlet())
-
- val inlet = TestInlet(graph)
-
- ups.connect(inlet)
- ups.disconnect()
-
- yield()
-
- assertEquals(0.0f, inlet.flowOutlet.capacity)
- }
-}
diff --git a/opendc-simulator/opendc-simulator-power/src/test/kotlin/org/opendc/simulator/power/TestInlet.kt b/opendc-simulator/opendc-simulator-power/src/test/kotlin/org/opendc/simulator/power/TestInlet.kt
deleted file mode 100644
index 1c06acf4..00000000
--- a/opendc-simulator/opendc-simulator-power/src/test/kotlin/org/opendc/simulator/power/TestInlet.kt
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2022 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.power
-
-import org.opendc.simulator.flow2.FlowGraph
-import org.opendc.simulator.flow2.FlowStage
-import org.opendc.simulator.flow2.FlowStageLogic
-import org.opendc.simulator.flow2.Outlet
-
-/**
- * A test inlet.
- */
-class TestInlet(graph: FlowGraph) : SimPowerInlet(), FlowStageLogic {
- private val stage = graph.newStage(this)
- val flowOutlet = stage.getOutlet("out")
-
- init {
- flowOutlet.push(100.0f)
- }
-
- override fun onUpdate(
- ctx: FlowStage,
- now: Long,
- ): Long = Long.MAX_VALUE
-
- override fun getFlowOutlet(): Outlet {
- return flowOutlet
- }
-}