summaryrefslogtreecommitdiff
path: root/opendc-simulator/opendc-simulator-compute/src/main/java
diff options
context:
space:
mode:
Diffstat (limited to 'opendc-simulator/opendc-simulator-compute/src/main/java')
-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/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/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/main/java/org/opendc/simulator/compute/SimNetworkInterface.java)54
-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-compute/src/main/java/org/opendc/simulator/compute/kernel/cpufreq/ScalingGovernorFactory.java)23
49 files changed, 2007 insertions, 4748 deletions
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/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/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/main/java/org/opendc/simulator/compute/SimNetworkInterface.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/memory/Memory.java
index 4b623e59..2656a99a 100644
--- 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/memory/Memory.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,32 +20,36 @@
* SOFTWARE.
*/
-package org.opendc.simulator.compute;
+package org.opendc.simulator.compute.memory;
-import org.opendc.simulator.flow2.Inlet;
-import org.opendc.simulator.flow2.Outlet;
+import org.opendc.simulator.compute.models.MemoryUnit;
+import org.opendc.simulator.engine.FlowGraph;
/**
- * A firmware interface to a network adapter.
+ * The [SimMemory] implementation for a machine.
*/
-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();
+public final class Memory {
+ // private final SimpleFlowSink sink;
+ private final MemoryUnit memoryUnit;
+
+ public Memory(FlowGraph graph, MemoryUnit memoryUnit) {
+
+ this.memoryUnit = memoryUnit;
+ // TODO: Fix this
+ // this.sink = new SimpleFlowSink(graph, (float) memoryUnit.getSize());
+ }
+
+ public double getCapacity() {
+ // return sink.getCapacity();
+ return 0.0f;
+ }
+
+ public MemoryUnit getMemoryUnit() {
+ return memoryUnit;
+ }
+
+ @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-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/workload/Workload.java
index 97a49879..cd34921a 100644
--- 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/workload/Workload.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,14 +20,17 @@
* SOFTWARE.
*/
-package org.opendc.simulator.compute.kernel.cpufreq;
+package org.opendc.simulator.compute.workload;
-/**
- * Factory interface for a {@link ScalingGovernor}.
- */
-public interface ScalingGovernorFactory {
- /**
- * Create the scaling logic for the specified {@link ScalingPolicy}.
- */
- ScalingGovernor newGovernor(ScalingPolicy policy);
+import org.opendc.simulator.engine.FlowSupplier;
+
+public interface Workload {
+
+ long getCheckpointInterval();
+
+ long getCheckpointDuration();
+
+ double getCheckpointIntervalScaling();
+
+ SimWorkload startWorkload(FlowSupplier supplier, long now);
}