summaryrefslogtreecommitdiff
path: root/opendc-simulator/opendc-simulator-compute/src/main
diff options
context:
space:
mode:
Diffstat (limited to 'opendc-simulator/opendc-simulator-compute/src/main')
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimAbstractMachine.java327
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimBareMetalMachine.java298
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimMachine.java (renamed from opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachine.kt)34
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimMachineContext.java (renamed from opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachineContext.kt)50
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimMemory.java (renamed from opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMemory.kt)20
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimNetworkInterface.java (renamed from opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimNetworkInterface.kt)24
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimProcessingUnit.java (renamed from opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimProcessingUnit.kt)37
-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.java (renamed from opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimStorageInterface.kt)22
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/device/SimNetworkAdapter.java (renamed from opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/device/SimNetworkAdapter.kt)16
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/device/SimPeripheral.java (renamed from opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/device/SimPeripheral.kt)12
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/SimHypervisor.java911
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/SimHypervisorCounters.java (renamed from opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimHypervisorCounters.kt)26
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/SimVirtualMachine.java (renamed from opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimVirtualMachine.kt)26
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/cpufreq/ScalingGovernor.java (renamed from opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ScalingGovernor.kt)30
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/cpufreq/ScalingGovernorFactory.java (renamed from opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/ConstantPowerModel.kt)15
-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.java (renamed from opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ScalingPolicy.kt)29
-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.java (renamed from opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/interference/VmInterferenceProfile.kt)49
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/MachineModel.java149
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/MemoryUnit.java100
-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/ProcessingUnit.java86
-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/power/CpuPowerModel.java (renamed from opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/PowerModel.kt)14
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/CpuPowerModels.java330
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimFlopsWorkload.java141
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimRuntimeWorkload.java131
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimTrace.java303
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimTraceFragment.java94
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimWorkload.java (renamed from opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimWorkload.kt)13
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimWorkloadLifecycle.java60
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimAbstractMachine.kt239
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimBareMetalMachine.kt130
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/device/SimPsu.kt114
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimHypervisor.kt442
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ConservativeScalingGovernor.kt66
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/OnDemandScalingGovernor.kt50
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PerformanceScalingGovernor.kt36
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PowerSaveScalingGovernor.kt36
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/interference/VmInterferenceDomain.kt131
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/interference/VmInterferenceMember.kt163
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/interference/VmInterferenceModel.kt191
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/MachineModel.kt54
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/MemoryUnit.kt38
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/NetworkAdapter.kt36
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/ProcessingNode.kt38
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/ProcessingUnit.kt36
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/StorageDevice.kt40
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/AsymptoticPowerModel.kt54
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/CubicPowerModel.kt41
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/InterpolationPowerModel.kt64
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/LinearPowerModel.kt42
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/MsePowerModel.kt49
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/PStatePowerDriver.kt60
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/PowerDriver.kt48
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/SimplePowerDriver.kt48
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/SqrtPowerModel.kt41
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/SquarePowerModel.kt41
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/ZeroIdlePowerDecorator.kt40
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimFlopsWorkload.kt54
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimRuntimeWorkload.kt54
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimTrace.kt218
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimTraceFragment.kt38
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkload.kt46
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimWorkloadLifecycle.kt82
72 files changed, 4473 insertions, 3045 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
new file mode 100644
index 00000000..cf5aed03
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimAbstractMachine.java
@@ -0,0 +1,327 @@
+/*
+ * 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.List;
+import java.util.Map;
+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;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Abstract implementation of the {@link SimMachine} interface.
+ */
+public abstract class SimAbstractMachine implements SimMachine {
+ private static final Logger LOGGER = LoggerFactory.getLogger(SimAbstractMachine.class);
+ private final MachineModel model;
+
+ private Context 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) {
+ if (activeContext != null) {
+ throw new IllegalStateException("A machine cannot run multiple workloads concurrently");
+ }
+
+ final Context ctx = createContext(workload, new HashMap<>(meta));
+ ctx.start();
+ return ctx;
+ }
+
+ @Override
+ public final void cancel() {
+ final Context context = activeContext;
+ if (context != null) {
+ context.shutdown();
+ }
+ }
+
+ /**
+ * Construct a new {@link Context} instance representing the active execution.
+ *
+ * @param workload The workload to start on the machine.
+ * @param meta The metadata to pass to the workload.
+ */
+ protected abstract Context createContext(SimWorkload workload, Map<String, Object> meta);
+
+ /**
+ * Return the active {@link Context} instance (if any).
+ */
+ protected Context getActiveContext() {
+ return activeContext;
+ }
+
+ /**
+ * The execution context in which the workload runs.
+ */
+ public abstract static class Context implements SimMachineContext {
+ private final SimAbstractMachine machine;
+ private final SimWorkload workload;
+ private final Map<String, Object> meta;
+ private boolean isClosed;
+
+ /**
+ * Construct a new {@link Context} 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.
+ */
+ public Context(SimAbstractMachine machine, SimWorkload workload, Map<String, Object> meta) {
+ this.machine = machine;
+ this.workload = workload;
+ this.meta = meta;
+ }
+
+ @Override
+ public final Map<String, Object> getMeta() {
+ return meta;
+ }
+
+ @Override
+ public final void shutdown() {
+ 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 cause) {
+ LOGGER.warn("Workload failed during onStop callback", cause);
+ }
+ }
+
+ /**
+ * Start this context.
+ */
+ final void start() {
+ try {
+ machine.activeContext = this;
+ workload.onStart(this);
+ } catch (Exception cause) {
+ LOGGER.warn("Workload failed during onStart callback", cause);
+ shutdown();
+ }
+ }
+
+ /**
+ * Run the stop procedures for the resources associated with the machine.
+ */
+ protected void doCancel() {
+ final FlowGraph graph = getMemory().getInput().getGraph();
+
+ for (SimProcessingUnit cpu : getCpus()) {
+ final Inlet inlet = cpu.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 String toString() {
+ return "SimAbstractMachine.Context";
+ }
+ }
+
+ /**
+ * The [SimMemory] implementation for a machine.
+ */
+ public static final class Memory implements SimMemory {
+ private final SimpleFlowSink sink;
+ private final List<MemoryUnit> models;
+
+ public Memory(FlowGraph graph, List<MemoryUnit> models) {
+ long memorySize = 0;
+ for (MemoryUnit mem : models) {
+ memorySize += mem.getSize();
+ }
+
+ this.sink = new SimpleFlowSink(graph, (float) memorySize);
+ this.models = models;
+ }
+
+ @Override
+ public double getCapacity() {
+ return sink.getCapacity();
+ }
+
+ @Override
+ public List<MemoryUnit> getModels() {
+ return models;
+ }
+
+ @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
new file mode 100644
index 00000000..aa7502d6
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimBareMetalMachine.java
@@ -0,0 +1,298 @@
+/*
+ * 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 org.opendc.simulator.compute.device.SimPeripheral;
+import org.opendc.simulator.compute.model.MachineModel;
+import org.opendc.simulator.compute.model.ProcessingUnit;
+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)}.
+ */
+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 List<Cpu> cpus;
+
+ 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);
+
+ int cpuIndex = 0;
+ final ArrayList<Cpu> cpus = new ArrayList<>();
+ this.cpus = cpus;
+ for (ProcessingUnit cpu : model.getCpus()) {
+ cpus.add(new Cpu(psu, cpu, cpuIndex++));
+ }
+
+ 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 Context context = (Context) getActiveContext();
+
+ if (context == null) {
+ return 0.0;
+ }
+
+ float capacity = 0.f;
+
+ for (SimProcessingUnit cpu : context.cpus) {
+ capacity += cpu.getFrequency();
+ }
+
+ return capacity;
+ }
+
+ /**
+ * The CPU demand of the machine in MHz.
+ */
+ public double getCpuDemand() {
+ final Context context = (Context) getActiveContext();
+
+ if (context == null) {
+ return 0.0;
+ }
+
+ float demand = 0.f;
+
+ for (SimProcessingUnit cpu : context.cpus) {
+ demand += cpu.getDemand();
+ }
+
+ return demand;
+ }
+
+ /**
+ * The CPU usage of the machine in MHz.
+ */
+ public double getCpuUsage() {
+ final Context context = (Context) getActiveContext();
+
+ if (context == null) {
+ return 0.0;
+ }
+
+ float rate = 0.f;
+
+ for (SimProcessingUnit cpu : context.cpus) {
+ rate += cpu.getSpeed();
+ }
+
+ return rate;
+ }
+
+ @Override
+ protected SimAbstractMachine.Context createContext(SimWorkload workload, Map<String, Object> meta) {
+ return new Context(this, workload, meta);
+ }
+
+ /**
+ * The execution context for a {@link SimBareMetalMachine}.
+ */
+ private static final class Context extends SimAbstractMachine.Context {
+ private final FlowGraph graph;
+ private final List<Cpu> cpus;
+ private final Memory memory;
+ private final List<NetworkAdapter> net;
+ private final List<StorageDevice> disk;
+
+ private Context(SimBareMetalMachine machine, SimWorkload workload, Map<String, Object> meta) {
+ super(machine, workload, meta);
+
+ this.graph = machine.graph;
+ this.cpus = machine.cpus;
+ this.memory = machine.memory;
+ this.net = machine.net;
+ this.disk = machine.disk;
+ }
+
+ @Override
+ public FlowGraph getGraph() {
+ return graph;
+ }
+
+ @Override
+ public List<? extends SimProcessingUnit> getCpus() {
+ return cpus;
+ }
+
+ @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 Cpu implements SimProcessingUnit {
+ private final SimPsu psu;
+ private final ProcessingUnit model;
+ private final InPort port;
+
+ private Cpu(SimPsu psu, ProcessingUnit model, int id) {
+ this.psu = psu;
+ this.model = model;
+ this.port = psu.getCpuPower(id, model);
+
+ this.port.pull((float) model.getFrequency());
+ }
+
+ @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(model.getFrequency(), frequency));
+ psu.setCpuFrequency(port, frequency);
+ }
+
+ @Override
+ public double getDemand() {
+ return port.getDemand();
+ }
+
+ @Override
+ public double getSpeed() {
+ return port.getRate();
+ }
+
+ @Override
+ public ProcessingUnit getModel() {
+ return model;
+ }
+
+ @Override
+ public Inlet getInput() {
+ return port;
+ }
+
+ @Override
+ public String toString() {
+ return "SimBareMetalMachine.Cpu[model=" + model + "]";
+ }
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachine.kt b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimMachine.java
index 94581e89..59599875 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachine.kt
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimMachine.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 AtLarge Research
+ * 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
@@ -20,40 +20,40 @@
* SOFTWARE.
*/
-package org.opendc.simulator.compute
+package org.opendc.simulator.compute;
-import org.opendc.simulator.compute.device.SimPeripheral
-import org.opendc.simulator.compute.model.MachineModel
-import org.opendc.simulator.compute.workload.SimWorkload
+import java.util.List;
+import java.util.Map;
+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 run a [SimWorkload].
+ * A generic machine that is able to execute {@link SimWorkload} objects.
*/
public interface SimMachine {
/**
- * The model of the machine containing its specifications.
+ * Return the model of the machine containing its specifications.
*/
- public val model: MachineModel
+ MachineModel getModel();
/**
- * The peripherals attached to the machine.
+ * Return the peripherals attached to the machine.
*/
- public val peripherals: List<SimPeripheral>
+ List<? extends SimPeripheral> getPeripherals();
/**
- * Start the specified [SimWorkload] on this machine.
+ * 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.
- * @return A [SimMachineContext] that represents the execution context for 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.
*/
- public fun startWorkload(workload: SimWorkload, meta: Map<String, Any> = emptyMap()): SimMachineContext
+ SimMachineContext startWorkload(SimWorkload workload, Map<String, Object> meta);
/**
- * Cancel the workload that is currently running on this machine.
- *
- * If no workload is active, this operation is a no-op.
+ * Cancel the active workload on this machine (if any).
*/
- public fun cancel()
+ void cancel();
}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachineContext.kt b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimMachineContext.java
index 5e3a7766..f6a3bd38 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMachineContext.kt
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimMachineContext.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 AtLarge Research
+ * 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
@@ -20,41 +20,55 @@
* SOFTWARE.
*/
-package org.opendc.simulator.compute
+package org.opendc.simulator.compute;
+
+import java.util.List;
+import java.util.Map;
+import org.opendc.simulator.compute.workload.SimWorkload;
+import org.opendc.simulator.flow2.FlowGraph;
/**
- * A simulated execution context in which a bootable image runs. This interface represents the
- * firmware interface between the running image (e.g. operating system) and the physical or virtual firmware on
- * which the image runs.
+ * 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 : AutoCloseable {
+public interface SimMachineContext {
+ /**
+ * Return the {@link FlowGraph} in which the workload executes.
+ */
+ FlowGraph getGraph();
+
/**
- * The metadata associated with the context.
+ * Return the metadata associated with the context.
+ * <p>
+ * Users can pass this metadata to the workload via {@link SimMachine#startWorkload(SimWorkload, Map)}.
*/
- public val meta: Map<String, Any>
+ Map<String, Object> getMeta();
/**
- * The CPUs available on the machine.
+ * Return the CPUs available on the machine.
*/
- public val cpus: List<SimProcessingUnit>
+ List<? extends SimProcessingUnit> getCpus();
/**
- * The memory interface of the machine.
+ * Return the memory interface of the machine.
*/
- public val memory: SimMemory
+ SimMemory getMemory();
/**
- * The network interfaces available to the workload.
+ * Return the network interfaces available to the workload.
*/
- public val net: List<SimNetworkInterface>
+ List<? extends SimNetworkInterface> getNetworkInterfaces();
/**
- * The storage devices available to the workload.
+ * Return the storage devices available to the workload.
*/
- public val storage: List<SimStorageInterface>
+ List<? extends SimStorageInterface> getStorageInterfaces();
/**
- * Stop the workload.
+ * Shutdown the workload.
*/
- public override fun close()
+ void shutdown();
}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMemory.kt b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimMemory.java
index b1aef495..4fcc64ab 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimMemory.kt
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimMemory.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 AtLarge Research
+ * 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
@@ -20,17 +20,23 @@
* SOFTWARE.
*/
-package org.opendc.simulator.compute
+package org.opendc.simulator.compute;
-import org.opendc.simulator.compute.model.MemoryUnit
-import org.opendc.simulator.flow.FlowConsumer
+import java.util.List;
+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 : FlowConsumer {
+public interface SimMemory extends FlowSink {
/**
- * The models representing the static information of the memory units supporting this interface.
+ * Return the total capacity of the memory (in MBs).
*/
- public val models: List<MemoryUnit>
+ double getCapacity();
+
+ /**
+ * Return the models representing the static information of the memory units supporting this interface.
+ */
+ List<MemoryUnit> getModels();
}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimNetworkInterface.kt b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimNetworkInterface.java
index 660b2871..4b623e59 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimNetworkInterface.kt
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimNetworkInterface.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 AtLarge Research
+ * 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
@@ -20,32 +20,32 @@
* SOFTWARE.
*/
-package org.opendc.simulator.compute
+package org.opendc.simulator.compute;
-import org.opendc.simulator.flow.FlowConsumer
-import org.opendc.simulator.flow.FlowSource
+import org.opendc.simulator.flow2.Inlet;
+import org.opendc.simulator.flow2.Outlet;
/**
* A firmware interface to a network adapter.
*/
public interface SimNetworkInterface {
/**
- * The name of the network interface.
+ * Return the name of the network interface.
*/
- public val name: String
+ String getName();
/**
- * The unidirectional bandwidth of the network interface in Mbps.
+ * Return the unidirectional bandwidth of the network interface in Mbps.
*/
- public val bandwidth: Double
+ double getBandwidth();
/**
- * The resource provider for the transmit channel of the network interface.
+ * Return the inlet for the "transmit" channel of the network interface.
*/
- public val tx: FlowConsumer
+ Inlet getTx();
/**
- * The resource consumer for the receive channel of the network interface.
+ * Return the outlet for the "receive" channel of the network interface.
*/
- public val rx: FlowSource
+ Outlet getRx();
}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimProcessingUnit.kt b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimProcessingUnit.java
index c9f36ece..3dbd3656 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimProcessingUnit.kt
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimProcessingUnit.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 AtLarge Research
+ * 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
@@ -20,22 +20,43 @@
* SOFTWARE.
*/
-package org.opendc.simulator.compute
+package org.opendc.simulator.compute;
-import org.opendc.simulator.compute.model.ProcessingUnit
-import org.opendc.simulator.flow.FlowConsumer
+import org.opendc.simulator.compute.model.ProcessingUnit;
+import org.opendc.simulator.flow2.sink.FlowSink;
/**
* A simulated processing unit.
*/
-public interface SimProcessingUnit : FlowConsumer {
+public interface SimProcessingUnit extends FlowSink {
/**
- * The capacity of the processing unit, which can be adjusted by the workload if supported by the machine.
+ * Return the base clock frequency of the processing unit (in MHz).
*/
- public override var capacity: Double
+ 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.
*/
- public val model: ProcessingUnit
+ ProcessingUnit getModel();
}
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
new file mode 100644
index 00000000..7f1f97a0
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimPsu.java
@@ -0,0 +1,71 @@
+/*
+ * 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.ProcessingUnit;
+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 getPowerUsage();
+
+ /**
+ * 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, ProcessingUnit 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
new file mode 100644
index 00000000..52d04052
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimPsuFactories.java
@@ -0,0 +1,214 @@
+/*
+ * 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.Clock;
+import org.jetbrains.annotations.NotNull;
+import org.opendc.simulator.compute.model.ProcessingUnit;
+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 getPowerUsage() {
+ return 0;
+ }
+
+ @Override
+ public double getEnergyUsage() {
+ return 0;
+ }
+
+ @Override
+ InPort getCpuPower(int id, ProcessingUnit 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 Clock clock;
+
+ private double targetFreq;
+ private double totalUsage;
+ private long lastUpdate;
+
+ private double powerUsage;
+ 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 getPowerUsage() {
+ return powerUsage;
+ }
+
+ @Override
+ public double getEnergyUsage() {
+ updateEnergyUsage(clock.millis());
+ return energyUsage;
+ }
+
+ @Override
+ InPort getCpuPower(int id, ProcessingUnit model) {
+ targetFreq += model.getFrequency();
+
+ 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);
+ powerUsage = 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 += powerUsage * 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
new file mode 100644
index 00000000..872e7016
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimPsuFactory.java
@@ -0,0 +1,38 @@
+/*
+ * 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/kotlin/org/opendc/simulator/compute/SimStorageInterface.kt b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimStorageInterface.java
index 3d648671..341122dc 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimStorageInterface.kt
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/SimStorageInterface.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 AtLarge Research
+ * 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
@@ -20,31 +20,31 @@
* SOFTWARE.
*/
-package org.opendc.simulator.compute
+package org.opendc.simulator.compute;
-import org.opendc.simulator.flow.FlowConsumer
+import org.opendc.simulator.flow2.Inlet;
/**
* A firmware interface to a storage device.
*/
public interface SimStorageInterface {
/**
- * The name of the storage device.
+ * Return the name of the network interface.
*/
- public val name: String
+ String getName();
/**
- * The capacity of the storage device in MBs.
+ * Return the capacity of the storage device in MBs.
*/
- public val capacity: Double
+ double getCapacity();
/**
- * The resource provider for the read operations of the storage device.
+ * Return the inlet for the read operations of the storage device.
*/
- public val read: FlowConsumer
+ Inlet getRead();
/**
- * The resource consumer for the write operation of the storage device.
+ * Return the inlet for the write operation of the storage device.
*/
- public val write: FlowConsumer
+ Inlet getWrite();
}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/device/SimNetworkAdapter.kt b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/device/SimNetworkAdapter.java
index dfb4ecf3..1c16ceff 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/device/SimNetworkAdapter.kt
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/device/SimNetworkAdapter.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 AtLarge Research
+ * 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
@@ -20,17 +20,17 @@
* SOFTWARE.
*/
-package org.opendc.simulator.compute.device
+package org.opendc.simulator.compute.device;
-import org.opendc.simulator.compute.SimMachine
-import org.opendc.simulator.network.SimNetworkPort
+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 [SimMachine].
+ * A simulated network interface card (NIC or network adapter) that can be attached to a {@link SimMachine}.
*/
-public abstract class SimNetworkAdapter : SimNetworkPort(), SimPeripheral {
+public abstract class SimNetworkAdapter extends SimNetworkPort implements SimPeripheral {
/**
- * The unidirectional bandwidth of the network adapter in Mbps.
+ * Return the unidirectional bandwidth of the network adapter (in Mbps).
*/
- public abstract val bandwidth: Double
+ public abstract double getBandwidth();
}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/device/SimPeripheral.kt b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/device/SimPeripheral.java
index 268271be..40bd268b 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/device/SimPeripheral.kt
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/device/SimPeripheral.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 AtLarge Research
+ * 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
@@ -20,14 +20,14 @@
* SOFTWARE.
*/
-package org.opendc.simulator.compute.device
+package org.opendc.simulator.compute.device;
-import org.opendc.simulator.compute.SimMachine
+import org.opendc.simulator.compute.SimMachine;
/**
- * A component that can be attached to a [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
+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
new file mode 100644
index 00000000..6e295837
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/SimHypervisor.java
@@ -0,0 +1,911 @@
+/*
+ * 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.Clock;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.SplittableRandom;
+import java.util.stream.Collectors;
+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.MachineModel;
+import org.opendc.simulator.compute.model.ProcessingUnit;
+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 Context activeContext;
+ private final ArrayList<VirtualMachine> vms = new ArrayList<>();
+ private final HvCounters counters = new HvCounters();
+
+ /**
+ * 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");
+ }
+
+ VirtualMachine vm = new VirtualMachine(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.
+ ((VirtualMachine) machine).close();
+ }
+ }
+
+ /**
+ * Return the CPU capacity of the hypervisor in MHz.
+ */
+ public double getCpuCapacity() {
+ final Context context = activeContext;
+
+ if (context == null) {
+ return 0.0;
+ }
+
+ return context.previousCapacity;
+ }
+
+ /**
+ * The CPU demand of the hypervisor in MHz.
+ */
+ public double getCpuDemand() {
+ final Context context = activeContext;
+
+ if (context == null) {
+ return 0.0;
+ }
+
+ return context.previousDemand;
+ }
+
+ /**
+ * The CPU usage of the hypervisor in MHz.
+ */
+ public double getCpuUsage() {
+ final Context 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 Context context = activeContext;
+ if (context == null) {
+ return false;
+ }
+
+ final FlowMultiplexer multiplexer = context.multiplexer;
+ return (multiplexer.getMaxInputs() - multiplexer.getInputCount())
+ >= model.getCpus().size();
+ }
+
+ @Override
+ public void onStart(SimMachineContext ctx) {
+ final Context context = new Context(ctx, muxFactory, scalingGovernorFactory, counters);
+ context.start();
+ activeContext = context;
+ }
+
+ @Override
+ public void onStop(SimMachineContext ctx) {
+ final Context context = activeContext;
+ if (context != null) {
+ activeContext = null;
+ context.stop();
+ }
+ }
+
+ /**
+ * The context which carries the state when the hypervisor is running on a machine.
+ */
+ private static final class Context implements FlowStageLogic {
+ private final SimMachineContext ctx;
+ private final FlowMultiplexer multiplexer;
+ private final FlowStage stage;
+ private final List<ScalingGovernor> scalingGovernors;
+ private final Clock clock;
+ private final HvCounters counters;
+
+ private long lastCounterUpdate;
+ private final double d;
+ private float previousDemand;
+ private float previousRate;
+ private float previousCapacity;
+
+ private Context(
+ 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();
+
+ if (scalingGovernorFactory != null) {
+ this.scalingGovernors = ctx.getCpus().stream()
+ .map(cpu -> scalingGovernorFactory.newGovernor(new ScalingPolicyImpl(cpu)))
+ .collect(Collectors.toList());
+ } else {
+ this.scalingGovernors = Collections.emptyList();
+ }
+
+ float cpuCapacity = 0.f;
+ final List<? extends SimProcessingUnit> cpus = ctx.getCpus();
+ for (SimProcessingUnit cpu : cpus) {
+ cpuCapacity += cpu.getFrequency();
+ }
+ this.d = cpus.size() / cpuCapacity;
+ }
+
+ /**
+ * Start the hypervisor on a new machine.
+ */
+ void start() {
+ final FlowGraph graph = ctx.getGraph();
+ final FlowMultiplexer multiplexer = this.multiplexer;
+
+ for (SimProcessingUnit cpu : ctx.getCpus()) {
+ graph.connect(multiplexer.newOutput(), cpu.getInput());
+ }
+
+ for (ScalingGovernor governor : scalingGovernors) {
+ governor.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 List<ScalingGovernor> scalingGovernors = this.scalingGovernors;
+
+ 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 (!scalingGovernors.isEmpty()) {
+ for (ScalingGovernor governor : scalingGovernors) {
+ governor.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.getModel().getFrequency();
+ }
+ }
+
+ /**
+ * A virtual machine running on the hypervisor.
+ */
+ private class VirtualMachine extends SimAbstractMachine implements SimVirtualMachine {
+ private boolean isClosed;
+ private final VmCounters counters = new VmCounters(this);
+
+ private VirtualMachine(MachineModel model) {
+ super(model);
+ }
+
+ @Override
+ public SimHypervisorCounters getCounters() {
+ return counters;
+ }
+
+ @Override
+ public double getCpuDemand() {
+ final VmContext context = (VmContext) getActiveContext();
+
+ if (context == null) {
+ return 0.0;
+ }
+
+ return context.previousDemand;
+ }
+
+ @Override
+ public double getCpuUsage() {
+ final VmContext context = (VmContext) getActiveContext();
+
+ if (context == null) {
+ return 0.0;
+ }
+
+ return context.usage;
+ }
+
+ @Override
+ 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 Context createContext(SimWorkload workload, Map<String, Object> meta) {
+ if (isClosed) {
+ throw new IllegalStateException("Virtual machine does not exist anymore");
+ }
+
+ final SimHypervisor.Context context = activeContext;
+ if (context == null) {
+ throw new IllegalStateException("Hypervisor is inactive");
+ }
+
+ return new VmContext(
+ context, this, random, interferenceDomain, counters, SimHypervisor.this.counters, workload, meta);
+ }
+
+ @Override
+ public Context getActiveContext() {
+ return super.getActiveContext();
+ }
+
+ void close() {
+ if (isClosed) {
+ return;
+ }
+
+ isClosed = true;
+ cancel();
+ }
+ }
+
+ /**
+ * A {@link SimAbstractMachine.Context} for a virtual machine instance.
+ */
+ private static final class VmContext extends SimAbstractMachine.Context implements FlowStageLogic {
+ private final Context context;
+ 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 Clock clock;
+
+ private final List<VCpu> cpus;
+ 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(
+ Context context,
+ VirtualMachine machine,
+ SplittableRandom random,
+ VmInterferenceDomain interferenceDomain,
+ VmCounters vmCounters,
+ HvCounters hvCounters,
+ SimWorkload workload,
+ Map<String, Object> meta) {
+ super(machine, workload, meta);
+
+ this.context = context;
+ this.random = random;
+ this.vmCounters = vmCounters;
+ this.hvCounters = hvCounters;
+ this.clock = context.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 = context.ctx.getGraph();
+ final FlowStage stage = graph.newStage(this);
+ this.stage = stage;
+ this.lastUpdate = clock.millis();
+ this.lastCounterUpdate = clock.millis();
+
+ final FlowMultiplexer multiplexer = context.multiplexer;
+ this.multiplexer = multiplexer;
+
+ final MachineModel model = machine.getModel();
+ final List<ProcessingUnit> cpuModels = model.getCpus();
+ final Inlet[] muxInlets = new Inlet[cpuModels.size()];
+ final ArrayList<VCpu> cpus = new ArrayList<>();
+
+ this.muxInlets = muxInlets;
+ this.cpus = cpus;
+
+ float capacity = 0.f;
+
+ for (int i = 0; i < cpuModels.size(); i++) {
+ final Inlet muxInlet = multiplexer.newInput();
+ muxInlets[i] = muxInlet;
+
+ final InPort input = stage.getInlet("cpu" + i);
+ final OutPort output = stage.getOutlet("mux" + i);
+
+ final Handler handler = new Handler(this, input, output);
+ input.setHandler(handler);
+ output.setHandler(handler);
+
+ final ProcessingUnit cpuModel = cpuModels.get(i);
+ capacity += cpuModel.getFrequency();
+
+ final VCpu cpu = new VCpu(cpuModel, input);
+ cpus.add(cpu);
+
+ graph.connect(output, muxInlet);
+ }
+ this.d = cpuModels.size() / capacity;
+
+ 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;
+
+ 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;
+ 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 List<? extends SimProcessingUnit> getCpus() {
+ return cpus;
+ }
+
+ @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)
+ context.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 ProcessingUnit model;
+ private final InPort input;
+
+ private VCpu(ProcessingUnit model, InPort input) {
+ this.model = model;
+ this.input = input;
+
+ input.pull((float) model.getFrequency());
+ }
+
+ @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 ProcessingUnit getModel() {
+ 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 Context context = activeContext;
+
+ if (context != null) {
+ context.updateCounters();
+ }
+ }
+ }
+
+ /**
+ * Implementation of {@link SimHypervisorCounters} for the virtual machine.
+ */
+ private static class VmCounters implements SimHypervisorCounters {
+ private final VirtualMachine vm;
+ private long cpuActiveTime;
+ private long cpuIdleTime;
+ private long cpuStealTime;
+ private long cpuLostTime;
+
+ private VmCounters(VirtualMachine 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/kotlin/org/opendc/simulator/compute/kernel/SimHypervisorCounters.kt b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/SimHypervisorCounters.java
index 63fee507..fc77e9d6 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimHypervisorCounters.kt
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/SimHypervisorCounters.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 AtLarge Research
+ * 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
@@ -20,34 +20,34 @@
* SOFTWARE.
*/
-package org.opendc.simulator.compute.kernel
+package org.opendc.simulator.compute.kernel;
/**
- * Performance counters of a [SimHypervisor].
+ * Performance counters of a {@link SimHypervisor}.
*/
public interface SimHypervisorCounters {
/**
- * The amount of time (in milliseconds) the CPUs of the hypervisor were actively running.
+ * Return the amount of time (in milliseconds) the CPUs of the hypervisor were actively running.
*/
- public val cpuActiveTime: Long
+ long getCpuActiveTime();
/**
- * The amount of time (in milliseconds) the CPUs of the hypervisor were idle.
+ * Return the amount of time (in milliseconds) the CPUs of the hypervisor were idle.
*/
- public val cpuIdleTime: Long
+ long getCpuIdleTime();
/**
- * The amount of CPU time (in milliseconds) that virtual machines were ready to run, but were not able to.
+ * Return the amount of CPU time (in milliseconds) that virtual machines were ready to run, but were not able to.
*/
- public val cpuStealTime: Long
+ long getCpuStealTime();
/**
- * The amount of CPU time (in milliseconds) that was lost due to interference between virtual machines.
+ * Return the amount of CPU time (in milliseconds) that was lost due to interference between virtual machines.
*/
- public val cpuLostTime: Long
+ long getCpuLostTime();
/**
- * Flush the counter values.
+ * Synchronize the counter values.
*/
- public fun flush()
+ void sync();
}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimVirtualMachine.kt b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/SimVirtualMachine.java
index 36219ef2..fdf5e47f 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimVirtualMachine.kt
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/SimVirtualMachine.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 AtLarge Research
+ * 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
@@ -20,31 +20,31 @@
* SOFTWARE.
*/
-package org.opendc.simulator.compute.kernel
+package org.opendc.simulator.compute.kernel;
-import org.opendc.simulator.compute.SimMachine
+import org.opendc.simulator.compute.SimMachine;
/**
- * A virtual [SimMachine] running on top of another [SimMachine].
+ * A virtual {@link SimMachine} running on top of another {@link SimMachine}.
*/
-public interface SimVirtualMachine : SimMachine {
+public interface SimVirtualMachine extends SimMachine {
/**
- * The resource counters associated with the virtual machine.
+ * Return the performance counters associated with the virtual machine.
*/
- public val counters: SimHypervisorCounters
+ SimHypervisorCounters getCounters();
/**
- * The CPU usage of the VM in MHz.
+ * Return the CPU usage of the VM in MHz.
*/
- public val cpuUsage: Double
+ double getCpuUsage();
/**
- * The CPU usage of the VM in MHz.
+ * Return the CPU usage of the VM in MHz.
*/
- public val cpuDemand: Double
+ double getCpuDemand();
/**
- * The CPU capacity of the VM in MHz.
+ * Return the CPU capacity of the VM in MHz.
*/
- public val cpuCapacity: Double
+ double getCpuCapacity();
}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ScalingGovernor.kt b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/cpufreq/ScalingGovernor.java
index d33827db..69a371e1 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ScalingGovernor.kt
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/cpufreq/ScalingGovernor.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 AtLarge Research
+ * 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
@@ -20,37 +20,27 @@
* SOFTWARE.
*/
-package org.opendc.simulator.compute.kernel.cpufreq
+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.
*
- * For more information, see the documentation of the Linux CPUFreq subsystem:
- * https://www.kernel.org/doc/html/latest/admin-guide/pm/cpufreq.html
+ * @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 {
/**
- * Create the scaling logic for the specified [policy]
+ * This method is invoked when the governor is started.
*/
- public fun createLogic(policy: ScalingPolicy): Logic
+ default void onStart() {}
/**
- * The logic of the scaling governor.
+ * This method is invoked when the governor should re-decide the frequency limits.
+ *
+ * @param load The load of the system.
*/
- public interface Logic {
- /**
- * This method is invoked when the governor is started.
- */
- public fun onStart() {}
-
- /**
- * This method is invoked when the governor should re-decide the frequency limits.
- *
- * @param load The load of the system.
- */
- public fun onLimit(load: Double) {}
- }
+ default void onLimit(double load) {}
}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/ConstantPowerModel.kt b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/cpufreq/ScalingGovernorFactory.java
index 0fe32b0d..97a49879 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/ConstantPowerModel.kt
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/cpufreq/ScalingGovernorFactory.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 AtLarge Research
+ * 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
@@ -20,13 +20,14 @@
* SOFTWARE.
*/
-package org.opendc.simulator.compute.power
+package org.opendc.simulator.compute.kernel.cpufreq;
/**
- * A power model which produces a constant value [power].
+ * Factory interface for a {@link ScalingGovernor}.
*/
-public class ConstantPowerModel(private val power: Double) : PowerModel {
- public override fun computePower(utilization: Double): Double = power
-
- override fun toString(): String = "ConstantPowerModel[power=$power]"
+public interface ScalingGovernorFactory {
+ /**
+ * Create the scaling logic for the specified {@link ScalingPolicy}.
+ */
+ ScalingGovernor newGovernor(ScalingPolicy policy);
}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/cpufreq/ScalingGovernors.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/cpufreq/ScalingGovernors.java
new file mode 100644
index 00000000..2b10ae59
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/cpufreq/ScalingGovernors.java
@@ -0,0 +1,190 @@
+/*
+ * 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/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ScalingPolicy.kt b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/cpufreq/ScalingPolicy.java
index f9351896..0cdb7a0b 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ScalingPolicy.kt
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/cpufreq/ScalingPolicy.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 AtLarge Research
+ * 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
@@ -20,32 +20,37 @@
* SOFTWARE.
*/
-package org.opendc.simulator.compute.kernel.cpufreq
+package org.opendc.simulator.compute.kernel.cpufreq;
-import org.opendc.simulator.compute.SimProcessingUnit
+import org.opendc.simulator.compute.SimProcessingUnit;
/**
- * An interface that holds the state managed by a [ScalingGovernor] and used by the underlying machine to control the
- * CPU frequencies.
+ * 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.
*/
- public val cpu: SimProcessingUnit
+ SimProcessingUnit getCpu();
/**
- * The target frequency which the CPU should attempt to attain.
+ * Return the target frequency which the CPU should attempt to attain.
*/
- public var target: Double
+ double getTarget();
/**
- * The minimum frequency to which the CPU may scale.
+ * Set the target frequency which the CPU should attempt to attain.
*/
- public val min: Double
+ void setTarget(double target);
/**
- * The maximum frequency to which the CPU may scale.
+ * Return the minimum frequency to which the CPU may scale.
*/
- public val max: Double
+ 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
new file mode 100644
index 00000000..cc671379
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/interference/VmInterferenceDomain.java
@@ -0,0 +1,136 @@
+/*
+ * 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
new file mode 100644
index 00000000..64cd5077
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/interference/VmInterferenceMember.java
@@ -0,0 +1,177 @@
+/*
+ * 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
new file mode 100644
index 00000000..e2093266
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/interference/VmInterferenceModel.java
@@ -0,0 +1,185 @@
+/*
+ * 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/kotlin/org/opendc/simulator/compute/kernel/interference/VmInterferenceProfile.kt b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/interference/VmInterferenceProfile.java
index 004dbd07..3f0c0a88 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/interference/VmInterferenceProfile.kt
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/kernel/interference/VmInterferenceProfile.java
@@ -20,32 +20,41 @@
* SOFTWARE.
*/
-package org.opendc.simulator.compute.kernel.interference
+package org.opendc.simulator.compute.kernel.interference;
/**
* A profile of a particular virtual machine describing its interference pattern with other virtual machines.
- *
- * @param model The model to which this profile belongs.
- * @property id The identifier of the profile inside the model.
- * @property membership The membership of the profile in the groups.
- * @param members The members in the model.
- * @param targets The targets in the model.
- * @param scores The scores in the model.
*/
-public class VmInterferenceProfile internal constructor(
- private val model: VmInterferenceModel,
- private val id: Int,
- private val membership: IntArray,
- private val members: Array<IntArray>,
- private val targets: DoubleArray,
- private val scores: DoubleArray
-) {
+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;
+
/**
- * Create a new [VmInterferenceMember] based on this profile for the specified [domain].
+ * Construct a {@link VmInterferenceProfile}.
*/
- internal fun newMember(domain: VmInterferenceDomain): VmInterferenceMember {
- return VmInterferenceMember(domain, model, id, membership, members, targets, scores)
+ 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;
}
- override fun toString(): String = "VmInterferenceProfile[id=$id]"
+ /**
+ * 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/model/MachineModel.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/MachineModel.java
new file mode 100644
index 00000000..2c625fce
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/MachineModel.java
@@ -0,0 +1,149 @@
+/*
+ * 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.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A description of the physical or virtual machine on which a bootable image runs.
+ */
+public final class MachineModel {
+ private final List<ProcessingUnit> cpus;
+ private final List<MemoryUnit> memory;
+ private final List<NetworkAdapter> net;
+ private final List<StorageDevice> storage;
+
+ /**
+ * Construct a {@link MachineModel} instance.
+ *
+ * @param cpus The list of processing units 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(
+ Iterable<ProcessingUnit> cpus,
+ Iterable<MemoryUnit> memory,
+ Iterable<NetworkAdapter> net,
+ Iterable<StorageDevice> storage) {
+ this.cpus = new ArrayList<>();
+ cpus.forEach(this.cpus::add);
+
+ this.memory = new ArrayList<>();
+ memory.forEach(this.memory::add);
+
+ this.net = new ArrayList<>();
+ net.forEach(this.net::add);
+
+ this.storage = new ArrayList<>();
+ storage.forEach(this.storage::add);
+ }
+
+ /**
+ * Construct a {@link MachineModel} instance.
+ *
+ * @param cpus The list of processing units available to the image.
+ * @param memory The list of memory units available to the image.
+ */
+ public MachineModel(Iterable<ProcessingUnit> cpus, Iterable<MemoryUnit> memory) {
+ this(cpus, memory, Collections.emptyList(), Collections.emptyList());
+ }
+
+ /**
+ * Optimize the [MachineModel] by merging all resources of the same type into a single resource with the combined
+ * capacity. Such configurations can be simulated more efficiently by OpenDC.
+ */
+ public MachineModel optimize() {
+ ProcessingUnit originalCpu = cpus.get(0);
+
+ double freq = 0.0;
+ for (ProcessingUnit cpu : cpus) {
+ freq += cpu.getFrequency();
+ }
+
+ ProcessingNode originalNode = originalCpu.getNode();
+ ProcessingNode processingNode = new ProcessingNode(
+ originalNode.getVendor(), originalNode.getModelName(), originalNode.getArchitecture(), 1);
+ ProcessingUnit processingUnit = new ProcessingUnit(processingNode, originalCpu.getId(), freq);
+
+ long memorySize = 0;
+ for (MemoryUnit mem : memory) {
+ memorySize += mem.getSize();
+ }
+ MemoryUnit memoryUnit = new MemoryUnit("Generic", "Generic", 3200.0, memorySize);
+
+ return new MachineModel(List.of(processingUnit), List.of(memoryUnit));
+ }
+
+ /**
+ * Return the processing units of this machine.
+ */
+ public List<ProcessingUnit> getCpus() {
+ return Collections.unmodifiableList(cpus);
+ }
+
+ /**
+ * Return the memory units of this machine.
+ */
+ public List<MemoryUnit> getMemory() {
+ return Collections.unmodifiableList(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 cpus.equals(that.cpus)
+ && memory.equals(that.memory)
+ && net.equals(that.net)
+ && storage.equals(that.storage);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(cpus, memory, net, storage);
+ }
+
+ @Override
+ public String toString() {
+ return "MachineModel[cpus=" + cpus + ",memory=" + memory + ",net=" + net + ",storage=" + storage + "]";
+ }
+}
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/model/MemoryUnit.java
new file mode 100644
index 00000000..4250f5a2
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/MemoryUnit.java
@@ -0,0 +1,100 @@
+/*
+ * 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 memory unit of a compute resource, either virtual or physical.
+ */
+public final class MemoryUnit {
+ private final String vendor;
+ private final String modelName;
+ private final double speed;
+ private final long size;
+
+ /**
+ * Construct a {@link ProcessingNode} instance.
+ *
+ * @param vendor The vendor of the storage device.
+ * @param modelName The model name of the device.
+ * @param speed The access speed of the memory in MHz.
+ * @param size The size of the memory unit in MBs.
+ */
+ public MemoryUnit(String vendor, String modelName, double speed, long size) {
+ this.vendor = vendor;
+ this.modelName = modelName;
+ this.speed = speed;
+ this.size = size;
+ }
+
+ /**
+ * 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 access speed of the memory in MHz.
+ */
+ public double getSpeed() {
+ return speed;
+ }
+
+ /**
+ * Return the size of the memory unit in MBs.
+ */
+ public long getSize() {
+ return size;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ MemoryUnit that = (MemoryUnit) o;
+ return Double.compare(that.speed, speed) == 0
+ && size == that.size
+ && vendor.equals(that.vendor)
+ && modelName.equals(that.modelName);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(vendor, modelName, speed, size);
+ }
+
+ @Override
+ public String toString() {
+ return "ProcessingNode[vendor='" + vendor + "',modelName='" + modelName + "',speed=" + speed + "MHz,size="
+ + size + "MB]";
+ }
+}
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
new file mode 100644
index 00000000..ff3daa40
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/NetworkAdapter.java
@@ -0,0 +1,88 @@
+/*
+ * 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
new file mode 100644
index 00000000..01a87b96
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/ProcessingNode.java
@@ -0,0 +1,100 @@
+/*
+ * 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/ProcessingUnit.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/ProcessingUnit.java
new file mode 100644
index 00000000..51a045d1
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/ProcessingUnit.java
@@ -0,0 +1,86 @@
+/*
+ * 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 single logical compute unit of processor node, either virtual or physical.
+ */
+public final class ProcessingUnit {
+ private final ProcessingNode node;
+ private final int id;
+ private final double frequency;
+
+ /**
+ * Construct a {@link ProcessingUnit} instance.
+ *
+ * @param node The processing node containing the CPU core.
+ * @param id The identifier of the CPU core within the processing node.
+ * @param frequency The clock rate of the CPU in MHz.
+ */
+ public ProcessingUnit(ProcessingNode node, int id, double frequency) {
+ this.node = node;
+ this.id = id;
+ this.frequency = frequency;
+ }
+
+ /**
+ * Return the processing node containing the CPU core.
+ */
+ public ProcessingNode getNode() {
+ return node;
+ }
+
+ /**
+ * Return the identifier of the CPU core within the processing node.
+ */
+ public int getId() {
+ return id;
+ }
+
+ /**
+ * Return the clock rate of the CPU in MHz.
+ */
+ public double getFrequency() {
+ return frequency;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ ProcessingUnit that = (ProcessingUnit) o;
+ return id == that.id && Double.compare(that.frequency, frequency) == 0 && Objects.equals(node, that.node);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(node, id, frequency);
+ }
+
+ @Override
+ public String toString() {
+ return "ProcessingUnit[node=" + node + ",id=" + id + ",frequency=" + frequency + "]";
+ }
+}
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
new file mode 100644
index 00000000..549ccc7e
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/model/StorageDevice.java
@@ -0,0 +1,112 @@
+/*
+ * 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/kotlin/org/opendc/simulator/compute/power/PowerModel.kt b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/CpuPowerModel.java
index decb2420..e023d098 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/PowerModel.kt
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/CpuPowerModel.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2021 AtLarge Research
+ * 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
@@ -20,19 +20,19 @@
* SOFTWARE.
*/
-package org.opendc.simulator.compute.power
+package org.opendc.simulator.compute.power;
-import org.opendc.simulator.compute.SimMachine
+import org.opendc.simulator.compute.SimMachine;
/**
- * A model for estimating the power usage of a [SimMachine].
+ * A model for estimating the power usage of a {@link SimMachine} based on the CPU usage.
*/
-public interface PowerModel {
+public interface CpuPowerModel {
/**
* Computes CPU power consumption for each host.
*
* @param utilization The CPU utilization percentage.
- * @return A [Double] value of CPU power consumption.
+ * @return A double value of CPU power consumption (in W).
*/
- public fun computePower(utilization: Double): Double
+ double computePower(double utilization);
}
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/power/CpuPowerModels.java
new file mode 100644
index 00000000..5d3d936b
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/CpuPowerModels.java
@@ -0,0 +1,330 @@
+/*
+ * 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.power;
+
+import java.util.Arrays;
+
+/**
+ * A collection {@link CpuPowerModel} implementations.
+ */
+public class CpuPowerModels {
+ private CpuPowerModels() {}
+
+ /**
+ * Construct a constant {@link CpuPowerModel}.
+ *
+ * @param power The power consumption fo the server at all times (in W).
+ */
+ public static CpuPowerModel constant(double power) {
+ return new ConstantPowerModel(power);
+ }
+
+ /**
+ * Construct a square root {@link CpuPowerModel} that is adapted from CloudSim.
+ *
+ * @param maxPower The maximum power draw of the server in W.
+ * @param idlePower The power draw of the server at its lowest utilization level in W.
+ */
+ public static CpuPowerModel sqrt(double maxPower, double idlePower) {
+ return new SqrtPowerModel(maxPower, idlePower);
+ }
+
+ /**
+ * Construct a linear {@link CpuPowerModel} that is adapted from CloudSim.
+ *
+ * @param maxPower The maximum power draw of the server in W.
+ * @param idlePower The power draw of the server at its lowest utilization level in W.
+ */
+ public static CpuPowerModel linear(double maxPower, double idlePower) {
+ return new LinearPowerModel(maxPower, idlePower);
+ }
+
+ /**
+ * Construct a square {@link CpuPowerModel} that is adapted from CloudSim.
+ *
+ * @param maxPower The maximum power draw of the server in W.
+ * @param idlePower The power draw of the server at its lowest utilization level in W.
+ */
+ public static CpuPowerModel square(double maxPower, double idlePower) {
+ return new SquarePowerModel(maxPower, idlePower);
+ }
+
+ /**
+ * Construct a cubic {@link CpuPowerModel} that is adapted from CloudSim.
+ *
+ * @param maxPower The maximum power draw of the server in W.
+ * @param idlePower The power draw of the server at its lowest utilization level in W.
+ */
+ public static CpuPowerModel cubic(double maxPower, double idlePower) {
+ return new CubicPowerModel(maxPower, idlePower);
+ }
+
+ /**
+ * Construct a {@link CpuPowerModel} that minimizes the mean squared error (MSE)
+ * to the actual power measurement by tuning the calibration parameter.
+ *
+ * @param maxPower The maximum power draw of the server in W.
+ * @param idlePower The power draw of the server at its lowest utilization level in W.
+ * @param calibrationFactor The parameter set to minimize the MSE.
+ * @see <a href="https://dl.acm.org/doi/abs/10.1145/1273440.1250665">
+ * Fan et al., Power provisioning for a warehouse-sized computer, ACM SIGARCH'07</a>
+ */
+ public static CpuPowerModel mse(double maxPower, double idlePower, double calibrationFactor) {
+ return new MsePowerModel(maxPower, idlePower, calibrationFactor);
+ }
+
+ /**
+ * Construct an asymptotic {@link CpuPowerModel} adapted from GreenCloud.
+ *
+ * @param maxPower The maximum power draw of the server in W.
+ * @param idlePower The power draw of the server at its lowest utilization level in W.
+ * @param asymUtil A utilization level at which the server attains asymptotic,
+ * i.e., close to linear power consumption versus the offered load.
+ * For most of the CPUs,a is in [0.2, 0.5].
+ * @param dvfs A flag indicates whether DVFS is enabled.
+ */
+ public static CpuPowerModel asymptotic(double maxPower, double idlePower, double asymUtil, boolean dvfs) {
+ return new AsymptoticPowerModel(maxPower, idlePower, asymUtil, dvfs);
+ }
+
+ /**
+ * Construct a linear interpolation model {@link CpuPowerModel} that is adapted from CloudSim.
+ *
+ * <p>
+ * The power consumption is linearly interpolated over the given power levels. In case of two values, the first
+ * represents 0% utilization, while the last value represent 100% utilization.
+ *
+ * @param powerLevels An array of power consumption steps (in W) for a specific CPU utilization.
+ * @see <a href="http://www.spec.org/power_ssj2008/results/res2011q1/">Machines used in the SPEC benchmark</a>
+ */
+ public static CpuPowerModel interpolate(double... powerLevels) {
+ return new InterpolationPowerModel(powerLevels.clone());
+ }
+
+ /**
+ * Decorate an existing {@link CpuPowerModel} to ensure that zero power consumption is reported when there is no
+ * utilization.
+ *
+ * @param delegate The existing {@link CpuPowerModel} to decorate.
+ */
+ public static CpuPowerModel zeroIdle(CpuPowerModel delegate) {
+ return new ZeroIdlePowerDecorator(delegate);
+ }
+
+ private static final class ConstantPowerModel implements CpuPowerModel {
+ private final double power;
+
+ ConstantPowerModel(double power) {
+ this.power = power;
+ }
+
+ @Override
+ public double computePower(double utilization) {
+ return power;
+ }
+
+ @Override
+ public String toString() {
+ return "ConstantPowerModel[power=" + power + "]";
+ }
+ }
+
+ private abstract static class MaxIdlePowerModel implements CpuPowerModel {
+ protected final double maxPower;
+ protected final double idlePower;
+
+ MaxIdlePowerModel(double maxPower, double idlePower) {
+ this.maxPower = maxPower;
+ this.idlePower = idlePower;
+ }
+
+ @Override
+ public String toString() {
+ return getClass().getSimpleName() + "[max=" + maxPower + ",idle=" + idlePower + "]";
+ }
+ }
+
+ private static final class SqrtPowerModel extends MaxIdlePowerModel {
+ private final double factor;
+
+ SqrtPowerModel(double maxPower, double idlePower) {
+ super(maxPower, idlePower);
+ this.factor = (maxPower - idlePower) / Math.sqrt(100);
+ }
+
+ @Override
+ public double computePower(double utilization) {
+ return idlePower + factor * Math.sqrt(utilization * 100);
+ }
+ }
+
+ private static final class LinearPowerModel extends MaxIdlePowerModel {
+ private final double factor;
+
+ LinearPowerModel(double maxPower, double idlePower) {
+ super(maxPower, idlePower);
+ this.factor = (maxPower - idlePower) / 100;
+ }
+
+ @Override
+ public double computePower(double utilization) {
+ return idlePower + factor * utilization * 100;
+ }
+ }
+
+ private static final class SquarePowerModel extends MaxIdlePowerModel {
+ private final double factor;
+
+ SquarePowerModel(double maxPower, double idlePower) {
+ super(maxPower, idlePower);
+ this.factor = (maxPower - idlePower) / Math.pow(100, 2);
+ }
+
+ @Override
+ public double computePower(double utilization) {
+ return idlePower + factor * Math.pow(utilization * 100, 2);
+ }
+ }
+
+ private static final class CubicPowerModel extends MaxIdlePowerModel {
+ private final double factor;
+
+ CubicPowerModel(double maxPower, double idlePower) {
+ super(maxPower, idlePower);
+ this.factor = (maxPower - idlePower) / Math.pow(100, 3);
+ }
+
+ @Override
+ public double computePower(double utilization) {
+ return idlePower + factor * Math.pow(utilization * 100, 3);
+ }
+ }
+
+ private static final class MsePowerModel extends MaxIdlePowerModel {
+ private final double calibrationFactor;
+ private final double factor;
+
+ MsePowerModel(double maxPower, double idlePower, double calibrationFactor) {
+ super(maxPower, idlePower);
+ this.calibrationFactor = calibrationFactor;
+ this.factor = (maxPower - idlePower) / 100;
+ }
+
+ @Override
+ public double computePower(double utilization) {
+ return idlePower + factor * (2 * utilization - Math.pow(utilization, calibrationFactor)) * 100;
+ }
+
+ @Override
+ public String toString() {
+ return "MsePowerModel[max=" + maxPower + ",idle=" + idlePower + ",calibrationFactor=" + calibrationFactor
+ + "]";
+ }
+ }
+
+ private static final class AsymptoticPowerModel extends MaxIdlePowerModel {
+ private final double asymUtil;
+ private final boolean dvfs;
+ private final double factor;
+
+ AsymptoticPowerModel(double maxPower, double idlePower, double asymUtil, boolean dvfs) {
+ super(maxPower, idlePower);
+ this.asymUtil = asymUtil;
+ this.dvfs = dvfs;
+ this.factor = (maxPower - idlePower) / 100;
+ }
+
+ @Override
+ public double computePower(double utilization) {
+ if (dvfs) {
+ return idlePower
+ + (factor * 100)
+ / 2
+ * (1
+ + Math.pow(utilization, 3)
+ - Math.pow(Math.E, -Math.pow(utilization, 3) / asymUtil));
+ } else {
+ return idlePower + (factor * 100) / 2 * (1 + utilization - Math.pow(Math.E, -utilization / asymUtil));
+ }
+ }
+
+ @Override
+ public String toString() {
+ return "AsymptoticPowerModel[max=" + maxPower + ",idle=" + idlePower + ",asymUtil=" + asymUtil + ",dvfs="
+ + dvfs + "]";
+ }
+ }
+
+ private static final class InterpolationPowerModel implements CpuPowerModel {
+ private final double[] powerLevels;
+
+ InterpolationPowerModel(double[] powerLevels) {
+ this.powerLevels = powerLevels;
+ }
+
+ @Override
+ public double computePower(double utilization) {
+ final double[] powerLevels = this.powerLevels;
+ double clampedUtilization = Math.min(1.0, Math.max(0.0, utilization));
+
+ if (utilization % 0.1 == 0.0) {
+ return powerLevels[(int) (clampedUtilization * 10)];
+ }
+
+ int utilizationFlr = (int) Math.floor(clampedUtilization * 10);
+ int utilizationCil = (int) Math.ceil(clampedUtilization * 10);
+ double powerFlr = powerLevels[utilizationFlr];
+ double powerCil = powerLevels[utilizationCil];
+ double delta = (powerCil - powerFlr) / 10;
+
+ return powerFlr + delta * (clampedUtilization - utilizationFlr / 10.0) * 100;
+ }
+
+ @Override
+ public String toString() {
+ return "InterpolationPowerModel[levels=" + Arrays.toString(powerLevels) + "]";
+ }
+ }
+
+ private static final class ZeroIdlePowerDecorator implements CpuPowerModel {
+ private final CpuPowerModel delegate;
+
+ ZeroIdlePowerDecorator(CpuPowerModel delegate) {
+ this.delegate = delegate;
+ }
+
+ @Override
+ public double computePower(double utilization) {
+ if (utilization == 0.0) {
+ return 0.0;
+ }
+
+ return delegate.computePower(utilization);
+ }
+
+ @Override
+ public String toString() {
+ return "ZeroIdlePowerDecorator[delegate=" + delegate + "]";
+ }
+ }
+}
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
new file mode 100644
index 00000000..255fd1b2
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimFlopsWorkload.java
@@ -0,0 +1,141 @@
+/*
+ * 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.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 {@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;
+
+ /**
+ * Construct a new {@link SimFlopsWorkload}.
+ *
+ * @param flops The number of floating point operations to perform for this task in MFLOPs.
+ * @param utilization A model of the CPU utilization of the application.
+ */
+ public 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;
+ }
+
+ @Override
+ public void onStart(SimMachineContext ctx) {
+ this.ctx = ctx;
+
+ final FlowGraph graph = ctx.getGraph();
+ final FlowStage stage = graph.newStage(this);
+ this.stage = stage;
+
+ final List<? extends SimProcessingUnit> cpus = ctx.getCpus();
+ final OutPort[] outputs = new OutPort[cpus.size()];
+ this.outputs = outputs;
+
+ for (int i = 0; i < cpus.size(); i++) {
+ final SimProcessingUnit cpu = cpus.get(i);
+ final OutPort output = stage.getOutlet("cpu" + i);
+
+ graph.connect(output, cpu.getInput());
+ outputs[i] = 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 String toString() {
+ return "SimFlopsWorkload[FLOPs=" + flops + ",utilization=" + utilization + "]";
+ }
+
+ @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;
+ }
+}
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
new file mode 100644
index 00000000..c3380b31
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimRuntimeWorkload.java
@@ -0,0 +1,131 @@
+/*
+ * 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.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 [SimWorkload] that models application execution as a single duration.
+ */
+public class SimRuntimeWorkload implements SimWorkload, FlowStageLogic {
+ private final long duration;
+ private final double utilization;
+
+ private SimMachineContext ctx;
+ private FlowStage stage;
+ private OutPort[] outputs;
+
+ private long remainingDuration;
+ private long lastUpdate;
+
+ /**
+ * Construct a new {@link SimRuntimeWorkload}.
+ *
+ * @param duration The duration of the workload in milliseconds.
+ * @param utilization A model of the CPU utilization of the application.
+ */
+ public SimRuntimeWorkload(long duration, double utilization) {
+ 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.duration = duration;
+ this.utilization = utilization;
+ }
+
+ @Override
+ public void onStart(SimMachineContext ctx) {
+ this.ctx = ctx;
+
+ final FlowGraph graph = ctx.getGraph();
+ final FlowStage stage = graph.newStage(this);
+ this.stage = stage;
+
+ final List<? extends SimProcessingUnit> cpus = ctx.getCpus();
+ final OutPort[] outputs = new OutPort[cpus.size()];
+ this.outputs = outputs;
+
+ for (int i = 0; i < cpus.size(); i++) {
+ final SimProcessingUnit cpu = cpus.get(i);
+ final OutPort output = stage.getOutlet("cpu" + i);
+
+ graph.connect(output, cpu.getInput());
+ outputs[i] = 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 long onUpdate(FlowStage ctx, long now) {
+ long lastUpdate = this.lastUpdate;
+ this.lastUpdate = now;
+
+ long delta = now - lastUpdate;
+ long duration = this.remainingDuration - delta;
+
+ 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
new file mode 100644
index 00000000..0bd2b2eb
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimTrace.java
@@ -0,0 +1,303 @@
+/*
+ * 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.Arrays;
+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 double[] usageCol;
+ private final long[] deadlineCol;
+ private final int[] coresCol;
+ private final int size;
+
+ /**
+ * Construct a {@link SimTrace} instance.
+ *
+ * @param usageCol The column containing the CPU usage of each fragment (in MHz).
+ * @param deadlineCol The column containing the ending timestamp for each fragment (in epoch millis).
+ * @param coresCol The column containing the utilized cores.
+ * @param size The number of fragments in the trace.
+ */
+ private SimTrace(double[] usageCol, long[] deadlineCol, int[] coresCol, int size) {
+ if (size < 0) {
+ throw new IllegalArgumentException("Invalid trace size");
+ } else if (usageCol.length < size) {
+ throw new IllegalArgumentException("Invalid number of usage entries");
+ } else if (deadlineCol.length < size) {
+ throw new IllegalArgumentException("Invalid number of deadline entries");
+ } else if (coresCol.length < size) {
+ throw new IllegalArgumentException("Invalid number of core entries");
+ }
+
+ this.usageCol = usageCol;
+ this.deadlineCol = deadlineCol;
+ this.coresCol = coresCol;
+ this.size = size;
+ }
+
+ /**
+ * Construct a {@link SimWorkload} for this trace.
+ *
+ * @param offset The offset for the timestamps.
+ */
+ public SimWorkload createWorkload(long offset) {
+ return new Workload(offset, usageCol, deadlineCol, coresCol, size);
+ }
+
+ /**
+ * Create a new {@link Builder} instance with the specified initial capacity.
+ */
+ public static Builder builder(int initialCapacity) {
+ return new Builder(initialCapacity);
+ }
+
+ /**
+ * Create a new {@link Builder} instance with a default initial capacity.
+ */
+ public static Builder builder() {
+ return builder(256);
+ }
+
+ /**
+ * 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(fragments.length);
+
+ for (SimTraceFragment fragment : fragments) {
+ builder.add(fragment.timestamp + fragment.duration, fragment.usage, fragment.cores);
+ }
+
+ 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(fragments.size());
+
+ for (SimTraceFragment fragment : fragments) {
+ builder.add(fragment.timestamp + fragment.duration, fragment.usage, fragment.cores);
+ }
+
+ return builder.build();
+ }
+
+ /**
+ * Builder class for a {@link SimTrace}.
+ */
+ public static final class Builder {
+ private double[] usageCol;
+ private long[] deadlineCol;
+ private int[] coresCol;
+
+ private int size;
+ private boolean isBuilt;
+
+ /**
+ * Construct a new {@link Builder} instance.
+ */
+ private Builder(int initialCapacity) {
+ this.usageCol = new double[initialCapacity];
+ this.deadlineCol = new long[initialCapacity];
+ this.coresCol = new int[initialCapacity];
+ }
+
+ /**
+ * Add a fragment to the trace.
+ *
+ * @param deadline 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 deadline, double usage, int cores) {
+ if (isBuilt) {
+ recreate();
+ }
+
+ int size = this.size;
+ double[] usageCol = this.usageCol;
+
+ if (size == usageCol.length) {
+ grow();
+ usageCol = this.usageCol;
+ }
+
+ deadlineCol[size] = deadline;
+ usageCol[size] = usage;
+ coresCol[size] = cores;
+
+ this.size++;
+ }
+
+ /**
+ * Build the {@link SimTrace} instance.
+ */
+ public SimTrace build() {
+ isBuilt = true;
+ return new SimTrace(usageCol, deadlineCol, coresCol, size);
+ }
+
+ /**
+ * Helper method to grow the capacity of the trace.
+ */
+ private void grow() {
+ int arraySize = usageCol.length;
+ int newSize = arraySize + (arraySize >> 1);
+
+ usageCol = Arrays.copyOf(usageCol, newSize);
+ deadlineCol = Arrays.copyOf(deadlineCol, newSize);
+ coresCol = Arrays.copyOf(coresCol, newSize);
+ }
+
+ /**
+ * 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;
+ usageCol = usageCol.clone();
+ deadlineCol = deadlineCol.clone();
+ coresCol = coresCol.clone();
+ }
+ }
+
+ /**
+ * Implementation of {@link SimWorkload} that executes a trace.
+ */
+ private static class Workload implements SimWorkload, FlowStageLogic {
+ private SimMachineContext ctx;
+ private FlowStage stage;
+ private OutPort[] outputs;
+ private int index;
+ private int coreCount;
+
+ private final long offset;
+ private final double[] usageCol;
+ private final long[] deadlineCol;
+ private final int[] coresCol;
+ private final int size;
+
+ private Workload(long offset, double[] usageCol, long[] deadlineCol, int[] coresCol, int size) {
+ this.offset = offset;
+ this.usageCol = usageCol;
+ this.deadlineCol = deadlineCol;
+ this.coresCol = coresCol;
+ this.size = size;
+ }
+
+ @Override
+ public void onStart(SimMachineContext ctx) {
+ this.ctx = ctx;
+
+ final FlowGraph graph = ctx.getGraph();
+ final List<? extends SimProcessingUnit> cpus = ctx.getCpus();
+
+ stage = graph.newStage(this);
+ coreCount = cpus.size();
+
+ final OutPort[] outputs = new OutPort[cpus.size()];
+ this.outputs = outputs;
+
+ for (int i = 0; i < cpus.size(); i++) {
+ final SimProcessingUnit cpu = cpus.get(i);
+ final OutPort output = stage.getOutlet("cpu" + i);
+
+ graph.connect(output, cpu.getInput());
+ outputs[i] = output;
+ }
+ }
+
+ @Override
+ public void onStop(SimMachineContext ctx) {
+ this.ctx = null;
+
+ final FlowStage stage = this.stage;
+
+ if (stage != null) {
+ this.stage = null;
+ stage.close();
+ }
+ }
+
+ @Override
+ public long onUpdate(FlowStage ctx, long now) {
+ int size = this.size;
+ long offset = this.offset;
+ long nowOffset = now - offset;
+
+ int index = this.index;
+
+ long[] deadlines = deadlineCol;
+ long deadline = deadlines[index];
+
+ while (deadline <= nowOffset && ++index < size) {
+ deadline = deadlines[index];
+ }
+
+ if (index >= size) {
+ final SimMachineContext machineContext = this.ctx;
+ if (machineContext != null) {
+ machineContext.shutdown();
+ }
+ ctx.close();
+ return Long.MAX_VALUE;
+ }
+
+ this.index = index;
+
+ int cores = Math.min(coreCount, coresCol[index]);
+ float usage = (float) usageCol[index] / cores;
+
+ final OutPort[] outputs = this.outputs;
+
+ for (int i = 0; i < cores; i++) {
+ outputs[i].push(usage);
+ }
+
+ for (int i = cores; i < outputs.length; i++) {
+ outputs[i].push(0.f);
+ }
+
+ return deadline + offset;
+ }
+ }
+}
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/SimTraceFragment.java
new file mode 100644
index 00000000..12c1348d
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimTraceFragment.java
@@ -0,0 +1,94 @@
+/*
+ * 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.Objects;
+
+/**
+ * A fragment of the workload trace.
+ */
+public final class SimTraceFragment {
+ final long timestamp;
+ final long duration;
+ final double usage;
+ final int cores;
+
+ /**
+ * Construct a {@link SimTraceFragment}.
+ *
+ * @param timestamp The timestamp at which the fragment starts (in epoch millis).
+ * @param duration The duration of the fragment (in milliseconds).
+ * @param usage The CPU usage during the fragment (in MHz).
+ * @param cores The amount of cores utilized during the fragment.
+ */
+ public SimTraceFragment(long timestamp, long duration, double usage, int cores) {
+ this.timestamp = timestamp;
+ this.duration = duration;
+ this.usage = usage;
+ this.cores = cores;
+ }
+
+ /**
+ * Return the timestamp at which the fragment starts (in epoch millis).
+ */
+ public long getTimestamp() {
+ return timestamp;
+ }
+
+ /**
+ * Return the duration of the fragment (in milliseconds).
+ */
+ public long getDuration() {
+ return duration;
+ }
+
+ /**
+ * Return the CPU usage during the fragment (in MHz).
+ */
+ public double getUsage() {
+ return usage;
+ }
+
+ /**
+ * Return the amount of cores utilized during the fragment.
+ */
+ public int getCores() {
+ return cores;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ SimTraceFragment that = (SimTraceFragment) o;
+ return timestamp == that.timestamp
+ && duration == that.duration
+ && Double.compare(that.usage, usage) == 0
+ && cores == that.cores;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(timestamp, duration, usage, cores);
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimWorkload.kt b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimWorkload.java
index 61c6e2ad..7be51265 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimWorkload.kt
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimWorkload.java
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2020 AtLarge Research
+ * 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
@@ -20,15 +20,16 @@
* SOFTWARE.
*/
-package org.opendc.simulator.compute.workload
+package org.opendc.simulator.compute.workload;
-import org.opendc.simulator.compute.SimMachineContext
+import org.opendc.simulator.compute.SimMachineContext;
/**
* A model that characterizes the runtime behavior of some particular workload.
*
+ * <p>
* Workloads are stateful objects that may be paused and resumed at a later moment. As such, be careful when using the
- * same [SimWorkload] from multiple contexts.
+ * same {@link SimWorkload} from multiple contexts.
*/
public interface SimWorkload {
/**
@@ -36,12 +37,12 @@ public interface SimWorkload {
*
* @param ctx The execution context in which the machine runs.
*/
- public fun onStart(ctx: SimMachineContext)
+ void onStart(SimMachineContext ctx);
/**
* This method is invoked when the workload is stopped.
*
* @param ctx The execution context in which the machine runs.
*/
- public fun onStop(ctx: SimMachineContext)
+ void onStop(SimMachineContext ctx);
}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimWorkloadLifecycle.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimWorkloadLifecycle.java
new file mode 100644
index 00000000..f0e2561f
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/SimWorkloadLifecycle.java
@@ -0,0 +1,60 @@
+/*
+ * 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.HashSet;
+import org.opendc.simulator.compute.SimMachineContext;
+
+/**
+ * A helper class to manage the lifecycle of a {@link SimWorkload}.
+ */
+public final class SimWorkloadLifecycle {
+ private final SimMachineContext ctx;
+ private final HashSet<Runnable> waiting = new HashSet<>();
+
+ /**
+ * Construct a {@link SimWorkloadLifecycle} instance.
+ *
+ * @param ctx The {@link SimMachineContext} of the workload.
+ */
+ public SimWorkloadLifecycle(SimMachineContext ctx) {
+ this.ctx = ctx;
+ }
+
+ /**
+ * Register a "completer" callback that must be invoked before ending the lifecycle of the workload.
+ */
+ public Runnable newCompleter() {
+ Runnable completer = new Runnable() {
+ @Override
+ public void run() {
+ final HashSet<Runnable> waiting = SimWorkloadLifecycle.this.waiting;
+ if (waiting.remove(this) && waiting.isEmpty()) {
+ ctx.shutdown();
+ }
+ }
+ };
+ waiting.add(completer);
+ return completer;
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimAbstractMachine.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimAbstractMachine.kt
deleted file mode 100644
index 71784567..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimAbstractMachine.kt
+++ /dev/null
@@ -1,239 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.simulator.compute
-
-import mu.KotlinLogging
-import org.opendc.simulator.compute.device.SimNetworkAdapter
-import org.opendc.simulator.compute.device.SimPeripheral
-import org.opendc.simulator.compute.model.MachineModel
-import org.opendc.simulator.compute.model.MemoryUnit
-import org.opendc.simulator.compute.model.NetworkAdapter
-import org.opendc.simulator.compute.model.StorageDevice
-import org.opendc.simulator.compute.workload.SimWorkload
-import org.opendc.simulator.flow.FlowConsumer
-import org.opendc.simulator.flow.FlowConvergenceListener
-import org.opendc.simulator.flow.FlowEngine
-import org.opendc.simulator.flow.FlowForwarder
-import org.opendc.simulator.flow.FlowSink
-import org.opendc.simulator.flow.FlowSource
-import org.opendc.simulator.flow.batch
-
-/**
- * Abstract implementation of the [SimMachine] interface.
- *
- * @param engine The engine to manage the machine's resources.
- * @param model The model of the machine.
- */
-public abstract class SimAbstractMachine(
- protected val engine: FlowEngine,
- final override val model: MachineModel
-) : SimMachine, FlowConvergenceListener {
- /**
- * The resources allocated for this machine.
- */
- public abstract val cpus: List<SimProcessingUnit>
-
- /**
- * The memory interface of the machine.
- */
- public val memory: SimMemory = Memory(FlowSink(engine, model.memory.sumOf { it.size }.toDouble()), model.memory)
-
- /**
- * The network interfaces available to the machine.
- */
- public val net: List<SimNetworkInterface> = model.net.mapIndexed { i, adapter -> NetworkAdapterImpl(engine, adapter, i) }
-
- /**
- * The network interfaces available to the machine.
- */
- public val storage: List<SimStorageInterface> = model.storage.mapIndexed { i, device -> StorageDeviceImpl(engine, device, i) }
-
- /**
- * The peripherals of the machine.
- */
- public override val peripherals: List<SimPeripheral> = net.map { it as SimNetworkAdapter }
-
- /**
- * The current active [Context].
- */
- private var _ctx: Context? = null
-
- override fun startWorkload(workload: SimWorkload, meta: Map<String, Any>): SimMachineContext {
- check(_ctx == null) { "A machine cannot run concurrently" }
-
- val ctx = Context(workload, meta)
- ctx.start()
- return ctx
- }
-
- override fun cancel() {
- _ctx?.close()
- }
-
- override fun onConverge(now: Long) {}
-
- /**
- * The execution context in which the workload runs.
- *
- * @param workload The workload that is running on the machine.
- * @param meta The metadata passed to the workload.
- */
- private inner class Context(
- private val workload: SimWorkload,
- override val meta: Map<String, Any>
- ) : SimMachineContext {
- /**
- * A flag to indicate that the context has been closed.
- */
- private var isClosed = false
-
- val engine: FlowEngine = this@SimAbstractMachine.engine
-
- /**
- * Start this context.
- */
- fun start() {
- try {
- _ctx = this
- engine.batch { workload.onStart(this) }
- } catch (cause: Throwable) {
- logger.warn(cause) { "Workload failed during onStart callback" }
- close()
- }
- }
-
- override val cpus: List<SimProcessingUnit> = this@SimAbstractMachine.cpus
-
- override val memory: SimMemory = this@SimAbstractMachine.memory
-
- override val net: List<SimNetworkInterface> = this@SimAbstractMachine.net
-
- override val storage: List<SimStorageInterface> = this@SimAbstractMachine.storage
-
- override fun close() {
- if (isClosed) {
- return
- }
-
- isClosed = true
- assert(_ctx == this) { "Invariant violation: multiple contexts active for a single machine" }
- _ctx = null
-
- // Cancel all the resources associated with the machine
- doCancel()
-
- try {
- workload.onStop(this)
- } catch (cause: Throwable) {
- logger.warn(cause) { "Workload failed during onStop callback" }
- }
- }
-
- /**
- * Run the stop procedures for the resources associated with the machine.
- */
- private fun doCancel() {
- engine.batch {
- for (cpu in cpus) {
- cpu.cancel()
- }
-
- memory.cancel()
-
- for (ifx in net) {
- (ifx as NetworkAdapterImpl).disconnect()
- }
-
- for (storage in storage) {
- val impl = storage as StorageDeviceImpl
- impl.read.cancel()
- impl.write.cancel()
- }
- }
- }
-
- override fun toString(): String = "SimAbstractMachine.Context"
- }
-
- /**
- * The [SimMemory] implementation for a machine.
- */
- private class Memory(source: FlowSink, override val models: List<MemoryUnit>) : SimMemory, FlowConsumer by source {
- override fun toString(): String = "SimAbstractMachine.Memory"
- }
-
- /**
- * The [SimNetworkAdapter] implementation for a machine.
- */
- private class NetworkAdapterImpl(
- engine: FlowEngine,
- model: NetworkAdapter,
- index: Int
- ) : SimNetworkAdapter(), SimNetworkInterface {
- override val name: String = "eth$index"
-
- override val bandwidth: Double = model.bandwidth
-
- override val provider: FlowConsumer
- get() = _rx
-
- override fun createConsumer(): FlowSource = _tx
-
- override val tx: FlowConsumer
- get() = _tx
- private val _tx = FlowForwarder(engine)
-
- override val rx: FlowSource
- get() = _rx
- private val _rx = FlowForwarder(engine)
-
- override fun toString(): String = "SimAbstractMachine.NetworkAdapterImpl[name=$name,bandwidth=$bandwidth]"
- }
-
- /**
- * The [SimStorageInterface] implementation for a machine.
- */
- private class StorageDeviceImpl(
- engine: FlowEngine,
- model: StorageDevice,
- index: Int
- ) : SimStorageInterface {
- override val name: String = "disk$index"
-
- override val capacity: Double = model.capacity
-
- override val read: FlowConsumer = FlowSink(engine, model.readBandwidth)
-
- override val write: FlowConsumer = FlowSink(engine, model.writeBandwidth)
-
- override fun toString(): String = "SimAbstractMachine.StorageDeviceImpl[name=$name,capacity=$capacity]"
- }
-
- private companion object {
- /**
- * The logging instance associated with this class.
- */
- @JvmStatic
- private val logger = KotlinLogging.logger {}
- }
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimBareMetalMachine.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimBareMetalMachine.kt
deleted file mode 100644
index 4c824440..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/SimBareMetalMachine.kt
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (c) 2020 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.simulator.compute
-
-import org.opendc.simulator.compute.device.SimPsu
-import org.opendc.simulator.compute.model.MachineModel
-import org.opendc.simulator.compute.model.ProcessingUnit
-import org.opendc.simulator.compute.power.PowerDriver
-import org.opendc.simulator.flow.FlowConsumer
-import org.opendc.simulator.flow.FlowEngine
-import org.opendc.simulator.flow.FlowSink
-import kotlin.math.max
-
-/**
- * A simulated bare-metal machine that is able to run a single workload.
- *
- * A [SimBareMetalMachine] is a stateful object, and you should be careful when operating this object concurrently. For
- * example, the class expects only a single concurrent call to [run].
- *
- * @param engine The [FlowEngine] to drive the simulation.
- * @param model The machine model to simulate.
- * @param powerDriver The power driver to use.
- * @param psu The power supply of the machine.
- */
-public class SimBareMetalMachine(
- engine: FlowEngine,
- model: MachineModel,
- powerDriver: PowerDriver,
- public val psu: SimPsu = SimPsu(500.0, mapOf(1.0 to 1.0))
-) : SimAbstractMachine(engine, model) {
- /**
- * The current power usage of the machine (without PSU loss) in W.
- */
- public val powerUsage: Double
- get() = _powerUsage
- private var _powerUsage = 0.0
-
- /**
- * The total energy usage of the machine (without PSU loss) in Joules.
- */
- public val energyUsage: Double
- get() {
- computeEnergyUsage(engine.clock.millis())
- return _energyUsage
- }
- private var _energyUsage = 0.0
- private var _energyLastComputation = 0L
-
- /**
- * The processing units of the machine.
- */
- override val cpus: List<SimProcessingUnit> = model.cpus.map { cpu ->
- Cpu(FlowSink(engine, cpu.frequency, this@SimBareMetalMachine), cpu)
- }
-
- /**
- * The logic of the power driver.
- */
- private val powerDriverLogic = powerDriver.createLogic(this, cpus)
-
- private var _lastConverge = Long.MAX_VALUE
-
- override fun onConverge(now: Long) {
- // Update the PSU stage
- psu.update()
-
- val lastConverge = _lastConverge
- _lastConverge = now
- val duration = max(0, now - lastConverge)
- if (duration > 0) {
- // Compute the power and energy usage of the machine
- computeEnergyUsage(now)
- }
-
- _powerUsage = powerDriverLogic.computePower()
- }
-
- init {
- psu.connect(powerDriverLogic)
- _powerUsage = powerDriverLogic.computePower()
- }
-
- /**
- * Helper method to compute total energy usage.
- */
- private fun computeEnergyUsage(now: Long) {
- val duration = max(0, now - _energyLastComputation)
- _energyLastComputation = now
-
- // Compute the energy usage of the machine
- _energyUsage += _powerUsage * (duration / 1000.0)
- }
-
- /**
- * A [SimProcessingUnit] of a bare-metal machine.
- */
- private class Cpu(
- private val source: FlowSink,
- override val model: ProcessingUnit
- ) : SimProcessingUnit, FlowConsumer by source {
- override var capacity: Double
- get() = source.capacity
- set(value) {
- // Clamp the capacity of the CPU between [0.0, maxFreq]
- source.capacity = value.coerceIn(0.0, model.frequency)
- }
-
- override fun toString(): String = "SimBareMetalMachine.Cpu[model=$model]"
- }
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/device/SimPsu.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/device/SimPsu.kt
deleted file mode 100644
index 3d3703ae..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/device/SimPsu.kt
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.simulator.compute.device
-
-import org.opendc.simulator.compute.power.PowerDriver
-import org.opendc.simulator.flow.FlowConnection
-import org.opendc.simulator.flow.FlowSource
-import org.opendc.simulator.power.SimPowerInlet
-import java.util.TreeMap
-
-/**
- * A power supply of a [SimBareMetalMachine].
- *
- * @param ratedOutputPower The rated output power of the PSU.
- * @param energyEfficiency The energy efficiency of the PSU for various power draws.
- */
-public class SimPsu(
- private val ratedOutputPower: Double,
- energyEfficiency: Map<Double, Double>
-) : SimPowerInlet() {
- /**
- * The power draw of the machine at this instant.
- */
- public val powerDraw: Double
- get() = _powerDraw
- private var _powerDraw = 0.0
-
- /**
- * The energy efficiency of the PSU at various power draws.
- */
- private val energyEfficiency = TreeMap(energyEfficiency)
-
- /**
- * The consumer context.
- */
- private var _ctx: FlowConnection? = null
-
- /**
- * The driver that is connected to the PSU.
- */
- private var _driver: PowerDriver.Logic? = null
-
- init {
- require(energyEfficiency.isNotEmpty()) { "Must specify at least one entry for energy efficiency of PSU" }
- }
-
- /**
- * Update the power draw of the PSU.
- */
- public fun update() {
- _ctx?.pull()
- }
-
- /**
- * Connect the specified [PowerDriver.Logic] to this PSU.
- */
- public fun connect(driver: PowerDriver.Logic) {
- check(_driver == null) { "PSU already connected" }
- _driver = driver
- update()
- }
-
- override fun createSource(): FlowSource = object : FlowSource {
- override fun onStart(conn: FlowConnection, now: Long) {
- _ctx = conn
- conn.shouldSourceConverge = true
- }
-
- override fun onStop(conn: FlowConnection, now: Long) {
- _ctx = null
- }
-
- override fun onPull(conn: FlowConnection, now: Long): Long {
- val powerDraw = computePowerDraw(_driver?.computePower() ?: 0.0)
- conn.push(powerDraw)
- return Long.MAX_VALUE
- }
-
- override fun onConverge(conn: FlowConnection, now: Long) {
- _powerDraw = conn.rate
- }
- }
-
- /**
- * Compute the power draw of the PSU including the power loss.
- */
- private fun computePowerDraw(load: Double): Double {
- val loadPercentage = (load / ratedOutputPower).coerceIn(0.0, 1.0)
- val efficiency = energyEfficiency.ceilingEntry(loadPercentage)?.value ?: 1.0
- return load / efficiency
- }
-
- override fun toString(): String = "SimPsu[draw=$_powerDraw]"
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimHypervisor.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimHypervisor.kt
deleted file mode 100644
index e1486d71..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/SimHypervisor.kt
+++ /dev/null
@@ -1,442 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.simulator.compute.kernel
-
-import org.opendc.simulator.compute.SimAbstractMachine
-import org.opendc.simulator.compute.SimMachine
-import org.opendc.simulator.compute.SimMachineContext
-import org.opendc.simulator.compute.SimProcessingUnit
-import org.opendc.simulator.compute.kernel.cpufreq.ScalingGovernor
-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.MachineModel
-import org.opendc.simulator.compute.model.ProcessingUnit
-import org.opendc.simulator.compute.workload.SimWorkload
-import org.opendc.simulator.flow.FlowConsumer
-import org.opendc.simulator.flow.FlowConvergenceListener
-import org.opendc.simulator.flow.FlowEngine
-import org.opendc.simulator.flow.mux.FlowMultiplexer
-import org.opendc.simulator.flow.mux.FlowMultiplexerFactory
-import java.util.SplittableRandom
-import kotlin.math.roundToLong
-
-/**
- * A SimHypervisor facilitates the execution of multiple concurrent [SimWorkload]s, while acting as a single workload
- * to another [SimMachine].
- *
- * @param engine The [FlowEngine] to drive the simulation.
- * @param muxFactory The factor for the [FlowMultiplexer] to multiplex the workloads.
- * @param random A randomness generator for the interference calculations.
- * @param scalingGovernor The scaling governor to use for scaling the CPU frequency of the underlying hardware.
- * @param interferenceDomain The interference domain to which the hypervisor belongs.
- */
-public class SimHypervisor(
- private val engine: FlowEngine,
- muxFactory: FlowMultiplexerFactory,
- private val random: SplittableRandom,
- private val scalingGovernor: ScalingGovernor? = null,
- private val interferenceDomain: VmInterferenceDomain = VmInterferenceDomain()
-) : SimWorkload, FlowConvergenceListener {
- /**
- * The [FlowMultiplexer] to multiplex the virtual machines.
- */
- private val mux = muxFactory.newMultiplexer(engine, this)
-
- /**
- * The virtual machines running on this hypervisor.
- */
- private val _vms = mutableSetOf<VirtualMachine>()
- public val vms: Set<SimMachine>
- get() = _vms
-
- /**
- * The resource counters associated with the hypervisor.
- */
- public val counters: SimHypervisorCounters
- get() = _counters
- private val _counters = CountersImpl(this)
-
- /**
- * The CPU capacity of the hypervisor in MHz.
- */
- public val cpuCapacity: Double
- get() = mux.capacity
-
- /**
- * The CPU demand of the hypervisor in MHz.
- */
- public val cpuDemand: Double
- get() = mux.demand
-
- /**
- * The CPU usage of the hypervisor in MHz.
- */
- public val cpuUsage: Double
- get() = mux.rate
-
- /**
- * The machine on which the hypervisor runs.
- */
- private lateinit var context: SimMachineContext
-
- /**
- * The scaling governors attached to the physical CPUs backing this hypervisor.
- */
- private val governors = mutableListOf<ScalingGovernor.Logic>()
-
- /* SimHypervisor */
- /**
- * Create a [SimMachine] instance on which users may run a [SimWorkload].
- *
- * @param model The machine to create.
- */
- public fun newMachine(model: MachineModel): SimVirtualMachine {
- require(canFit(model)) { "Machine does not fit" }
- val vm = VirtualMachine(model)
- _vms.add(vm)
- return vm
- }
-
- /**
- * Remove the specified [machine] from the hypervisor.
- *
- * @param machine The machine to remove.
- */
- public fun removeMachine(machine: SimVirtualMachine) {
- if (_vms.remove(machine)) {
- // This cast must always succeed, since `_vms` only contains `VirtualMachine` types.
- (machine as VirtualMachine).close()
- }
- }
-
- /**
- * Determine whether the specified machine characterized by [model] can fit on this hypervisor at this moment.
- */
- public fun canFit(model: MachineModel): Boolean {
- return (mux.maxInputs - mux.inputs.size) >= model.cpus.size
- }
-
- /* SimWorkload */
- override fun onStart(ctx: SimMachineContext) {
- context = ctx
-
- _cpuCount = ctx.cpus.size
- _cpuCapacity = ctx.cpus.sumOf { it.model.frequency }
- _counters.d = _cpuCount / _cpuCapacity * 1000L
-
- // Clear the existing outputs of the multiplexer
- mux.clearOutputs()
-
- for (cpu in ctx.cpus) {
- val governor = scalingGovernor?.createLogic(ScalingPolicyImpl(cpu))
- if (governor != null) {
- governors.add(governor)
- governor.onStart()
- }
-
- cpu.startConsumer(mux.newOutput())
- }
- }
-
- override fun onStop(ctx: SimMachineContext) {}
-
- private var _cpuCount = 0
- private var _cpuCapacity = 0.0
- private var _lastConverge = engine.clock.millis()
-
- /* FlowConvergenceListener */
- override fun onConverge(now: Long) {
- val lastConverge = _lastConverge
- _lastConverge = now
- val delta = now - lastConverge
-
- if (delta > 0) {
- _counters.record()
-
- val mux = mux
- val load = mux.rate / mux.capacity.coerceAtLeast(1.0)
- val random = random
-
- for (vm in _vms) {
- vm._counters.record(random, load)
- }
- }
-
- val load = cpuDemand / cpuCapacity
- for (governor in governors) {
- governor.onLimit(load)
- }
- }
-
- /**
- * A virtual machine running on the hypervisor.
- *
- * @param model The machine model of the virtual machine.
- */
- private inner class VirtualMachine(model: MachineModel) : SimAbstractMachine(engine, model), SimVirtualMachine, AutoCloseable {
- /**
- * A flag to indicate that the machine is closed.
- */
- private var isClosed = false
-
- /**
- * The vCPUs of the machine.
- */
- override val cpus = model.cpus.map { cpu -> VCpu(mux, mux.newInput(cpu.frequency), cpu) }
-
- /**
- * The resource counters associated with the hypervisor.
- */
- override val counters: SimHypervisorCounters
- get() = _counters
-
- @JvmField val _counters = VmCountersImpl(cpus, null)
-
- /**
- * The CPU capacity of the hypervisor in MHz.
- */
- override val cpuCapacity: Double
- get() = cpus.sumOf(FlowConsumer::capacity)
-
- /**
- * The CPU demand of the hypervisor in MHz.
- */
- override val cpuDemand: Double
- get() = cpus.sumOf(FlowConsumer::demand)
-
- /**
- * The CPU usage of the hypervisor in MHz.
- */
- override val cpuUsage: Double
- get() = cpus.sumOf(FlowConsumer::rate)
-
- override fun startWorkload(workload: SimWorkload, meta: Map<String, Any>): SimMachineContext {
- check(!isClosed) { "Machine is closed" }
-
- val profile = meta["interference-profile"] as? VmInterferenceProfile
- val interferenceMember = if (profile != null) interferenceDomain.join(profile) else null
-
- val counters = _counters
- counters.member = interferenceMember
-
- return super.startWorkload(
- object : SimWorkload {
- override fun onStart(ctx: SimMachineContext) {
- try {
- interferenceMember?.activate()
- workload.onStart(ctx)
- } catch (cause: Throwable) {
- interferenceMember?.deactivate()
- throw cause
- }
- }
-
- override fun onStop(ctx: SimMachineContext) {
- interferenceMember?.deactivate()
- counters.member = null
- workload.onStop(ctx)
- }
- },
- meta
- )
- }
-
- override fun close() {
- if (isClosed) {
- return
- }
-
- isClosed = true
- cancel()
-
- for (cpu in cpus) {
- cpu.close()
- }
- }
- }
-
- /**
- * A [SimProcessingUnit] of a virtual machine.
- */
- private class VCpu(
- private val switch: FlowMultiplexer,
- private val source: FlowConsumer,
- override val model: ProcessingUnit
- ) : SimProcessingUnit, FlowConsumer by source {
- override var capacity: Double
- get() = source.capacity
- set(_) = TODO("Capacity changes on vCPU not supported")
-
- override fun toString(): String = "SimAbstractHypervisor.VCpu[model=$model]"
-
- /**
- * Close the CPU
- */
- fun close() {
- switch.removeInput(source)
- }
-
- fun flush() {
- switch.flushCounters(source)
- }
- }
-
- /**
- * A [ScalingPolicy] for a physical CPU of the hypervisor.
- */
- private class ScalingPolicyImpl(override val cpu: SimProcessingUnit) : ScalingPolicy {
- override var target: Double
- get() = cpu.capacity
- set(value) {
- cpu.capacity = value
- }
-
- override val max: Double = cpu.model.frequency
-
- override val min: Double = 0.0
- }
-
- /**
- * Implementation of [SimHypervisorCounters].
- */
- private class CountersImpl(private val hv: SimHypervisor) : SimHypervisorCounters {
- @JvmField var d = 1.0 // Number of CPUs divided by total CPU capacity
-
- override val cpuActiveTime: Long
- get() = _cpuTime[0]
- override val cpuIdleTime: Long
- get() = _cpuTime[1]
- override val cpuStealTime: Long
- get() = _cpuTime[2]
- override val cpuLostTime: Long
- get() = _cpuTime[3]
-
- val _cpuTime = LongArray(4)
- private val _previous = DoubleArray(3)
-
- /**
- * Record the CPU time of the hypervisor.
- */
- fun record() {
- val cpuTime = _cpuTime
- val previous = _previous
- val counters = hv.mux.counters
-
- val demand = counters.demand
- val actual = counters.actual
- val remaining = counters.remaining
-
- val demandDelta = demand - previous[0]
- val actualDelta = actual - previous[1]
- val remainingDelta = remaining - previous[2]
-
- previous[0] = demand
- previous[1] = actual
- previous[2] = remaining
-
- cpuTime[0] += (actualDelta * d).roundToLong()
- cpuTime[1] += (remainingDelta * d).roundToLong()
- cpuTime[2] += ((demandDelta - actualDelta) * d).roundToLong()
- }
-
- override fun flush() {
- hv.mux.flushCounters()
- record()
- }
- }
-
- /**
- * A [SimHypervisorCounters] implementation for a virtual machine.
- */
- private inner class VmCountersImpl(
- private val cpus: List<VCpu>,
- @JvmField var member: VmInterferenceMember?
- ) : SimHypervisorCounters {
- private val d = cpus.size / cpus.sumOf { it.model.frequency } * 1000
-
- override val cpuActiveTime: Long
- get() = _cpuTime[0]
- override val cpuIdleTime: Long
- get() = _cpuTime[1]
- override val cpuStealTime: Long
- get() = _cpuTime[2]
- override val cpuLostTime: Long
- get() = _cpuTime[3]
-
- private val _cpuTime = LongArray(4)
- private val _previous = DoubleArray(3)
-
- /**
- * Record the CPU time of the hypervisor.
- */
- fun record(random: SplittableRandom, load: Double) {
- val cpuTime = _cpuTime
- val previous = _previous
-
- var demand = 0.0
- var actual = 0.0
- var remaining = 0.0
-
- for (cpu in cpus) {
- val counters = cpu.counters
-
- actual += counters.actual
- demand += counters.demand
- remaining += counters.remaining
- }
-
- val demandDelta = demand - previous[0]
- val actualDelta = actual - previous[1]
- val remainingDelta = remaining - previous[2]
-
- previous[0] = demand
- previous[1] = actual
- previous[2] = remaining
-
- val d = d
- cpuTime[0] += (actualDelta * d).roundToLong()
- cpuTime[1] += (remainingDelta * d).roundToLong()
- cpuTime[2] += ((demandDelta - actualDelta) * d).roundToLong()
-
- // Compute the performance penalty due to flow interference
- val member = member
- if (member != null) {
- val penalty = 1 - member.apply(random, load)
- val interference = (actualDelta * d * penalty).roundToLong()
-
- if (interference > 0) {
- cpuTime[3] += interference
- _counters._cpuTime[3] += interference
- }
- }
- }
-
- override fun flush() {
- for (cpu in cpus) {
- cpu.flush()
- }
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ConservativeScalingGovernor.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ConservativeScalingGovernor.kt
deleted file mode 100644
index 1a03221d..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/ConservativeScalingGovernor.kt
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.simulator.compute.kernel.cpufreq
-
-/**
- * A CPUFreq [ScalingGovernor] that models the conservative scaling governor in the Linux kernel.
- */
-public class ConservativeScalingGovernor(public val threshold: Double = 0.8, private val stepSize: Double = -1.0) :
- ScalingGovernor {
- override fun createLogic(policy: ScalingPolicy): ScalingGovernor.Logic = object : ScalingGovernor.Logic {
- /**
- * The step size to use.
- */
- private val stepSize = if (this@ConservativeScalingGovernor.stepSize < 0) {
- // https://github.com/torvalds/linux/blob/master/drivers/cpufreq/cpufreq_conservative.c#L33
- policy.max * 0.05
- } else {
- this@ConservativeScalingGovernor.stepSize.coerceAtMost(policy.max)
- }
-
- /**
- * The previous load of the CPU.
- */
- private var previousLoad = threshold
-
- override fun onStart() {
- policy.target = policy.min
- }
-
- override fun onLimit(load: Double) {
- val currentTarget = policy.target
- if (load > threshold) {
- // Check for load increase (see: https://github.com/torvalds/linux/blob/master/drivers/cpufreq/cpufreq_conservative.c#L102)
- val step = when {
- load > previousLoad -> stepSize
- load < previousLoad -> -stepSize
- else -> 0.0
- }
- policy.target = (currentTarget + step).coerceIn(policy.min, policy.max)
- }
- previousLoad = load
- }
- }
-
- override fun toString(): String = "ConservativeScalingGovernor[threshold=$threshold,stepSize=$stepSize]"
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/OnDemandScalingGovernor.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/OnDemandScalingGovernor.kt
deleted file mode 100644
index aef15ce9..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/OnDemandScalingGovernor.kt
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.simulator.compute.kernel.cpufreq
-
-/**
- * A CPUFreq [ScalingGovernor] that models the on-demand scaling governor in the Linux kernel.
- */
-public class OnDemandScalingGovernor(public val threshold: Double = 0.8) : ScalingGovernor {
- override fun createLogic(policy: ScalingPolicy): ScalingGovernor.Logic = object : ScalingGovernor.Logic {
- /**
- * The multiplier used for the linear frequency scaling.
- */
- private val multiplier = (policy.max - policy.min) / 100
-
- override fun onStart() {
- policy.target = policy.min
- }
-
- override fun onLimit(load: Double) {
- policy.target = if (load < threshold) {
- /* Proportional scaling (see: https://github.com/torvalds/linux/blob/master/drivers/cpufreq/cpufreq_ondemand.c#L151). */
- policy.min + load * multiplier
- } else {
- policy.max
- }
- }
- }
-
- override fun toString(): String = "OnDemandScalingGovernor[threshold=$threshold]"
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PerformanceScalingGovernor.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PerformanceScalingGovernor.kt
deleted file mode 100644
index 13109a9a..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PerformanceScalingGovernor.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.simulator.compute.kernel.cpufreq
-
-/**
- * A CPUFreq [ScalingGovernor] that causes the highest possible frequency to be requested from the resource.
- */
-public class PerformanceScalingGovernor : ScalingGovernor {
- override fun createLogic(policy: ScalingPolicy): ScalingGovernor.Logic = object : ScalingGovernor.Logic {
- override fun onStart() {
- policy.target = policy.max
- }
- }
-
- override fun toString(): String = "PerformanceScalingGovernor"
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PowerSaveScalingGovernor.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PowerSaveScalingGovernor.kt
deleted file mode 100644
index 32c0703a..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/cpufreq/PowerSaveScalingGovernor.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.simulator.compute.kernel.cpufreq
-
-/**
- * A CPUFreq [ScalingGovernor] that causes the lowest possible frequency to be requested from the resource.
- */
-public class PowerSaveScalingGovernor : ScalingGovernor {
- override fun createLogic(policy: ScalingPolicy): ScalingGovernor.Logic = object : ScalingGovernor.Logic {
- override fun onStart() {
- policy.target = policy.min
- }
- }
-
- override fun toString(): String = "PowerSaveScalingGovernor"
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/interference/VmInterferenceDomain.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/interference/VmInterferenceDomain.kt
deleted file mode 100644
index 6861823b..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/interference/VmInterferenceDomain.kt
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright (c) 2022 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.simulator.compute.kernel.interference
-
-import java.util.ArrayDeque
-import java.util.ArrayList
-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 class VmInterferenceDomain {
- /**
- * A cache to maintain a mapping between the active profiles in this domain.
- */
- private val cache = WeakHashMap<VmInterferenceProfile, VmInterferenceMember>()
-
- /**
- * The set of members active in this domain.
- */
- private val activeKeys = ArrayList<VmInterferenceMember>()
-
- /**
- * Queue of participants that will be removed or added to the active groups.
- */
- private val participants = ArrayDeque<VmInterferenceMember>()
-
- /**
- * Join this interference domain with the specified [profile] and return the [VmInterferenceMember] associated with
- * the profile. If the member does not exist, it will be created.
- */
- public fun join(profile: VmInterferenceProfile): VmInterferenceMember {
- return cache.computeIfAbsent(profile) { key -> key.newMember(this) }
- }
-
- /**
- * Mark the specified [member] as active in this interference domain.
- */
- internal fun activate(member: VmInterferenceMember) {
- val activeKeys = activeKeys
- val pos = activeKeys.binarySearch(member)
- if (pos < 0) {
- activeKeys.add(-pos - 1, member)
- }
-
- computeActiveGroups(activeKeys, member)
- }
-
- /**
- * Mark the specified [member] as inactive in this interference domain.
- */
- internal fun deactivate(member: VmInterferenceMember) {
- val activeKeys = activeKeys
- activeKeys.remove(member)
- computeActiveGroups(activeKeys, member)
- }
-
- /**
- * (Re-)compute the active groups.
- */
- private fun computeActiveGroups(activeKeys: ArrayList<VmInterferenceMember>, member: VmInterferenceMember) {
- if (activeKeys.isEmpty()) {
- return
- }
-
- val groups = member.membership
- val members = member.members
- val participants = participants
-
- for (group in groups) {
- val groupMembers = members[group]
-
- var i = 0
- var j = 0
- var intersection = 0
-
- // Compute the intersection of the group members and the current active members
- while (i < groupMembers.size && j < activeKeys.size) {
- val l = groupMembers[i]
- val rightEntry = activeKeys[j]
- val 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) {
- val participant = participants.poll() ?: break
-
- if (intersection <= 1) {
- participant.removeGroup(group)
- } else {
- participant.addGroup(group)
- }
- }
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/interference/VmInterferenceMember.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/interference/VmInterferenceMember.kt
deleted file mode 100644
index 4b56a058..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/interference/VmInterferenceMember.kt
+++ /dev/null
@@ -1,163 +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.SplittableRandom
-
-/**
- * A participant of an interference domain.
- */
-public class VmInterferenceMember(
- private val domain: VmInterferenceDomain,
- private val model: VmInterferenceModel,
- @JvmField internal val id: Int,
- @JvmField internal val membership: IntArray,
- @JvmField internal val members: Array<IntArray>,
- private val targets: DoubleArray,
- private val scores: DoubleArray
-) : Comparable<VmInterferenceMember> {
- /**
- * The active groups to which the key belongs.
- */
- private var groups: IntArray = IntArray(2)
- private var groupsSize: Int = 0
-
- /**
- * The number of users of the interference key.
- */
- private var refCount: Int = 0
-
- /**
- * Mark this member as active in this interference domain.
- */
- public fun activate() {
- if (refCount++ <= 0) {
- domain.activate(this)
- }
- }
-
- /**
- * Mark this member as inactive in this interference domain.
- */
- public fun 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 fun apply(random: SplittableRandom, load: Double): Double {
- val groupsSize = groupsSize
-
- if (groupsSize == 0) {
- return 1.0
- }
-
- val groups = groups
- val targets = targets
-
- var low = 0
- var high = groupsSize - 1
- var group = -1
-
- // Perform binary search over the groups based on target load
- while (low <= high) {
- val mid = low + high ushr 1
- val midGroup = groups[mid]
- val target = targets[midGroup]
-
- if (target < load) {
- low = mid + 1
- group = midGroup
- } else if (target > load) {
- high = mid - 1
- } else {
- group = midGroup
- break
- }
- }
-
- return if (group >= 0 && random.nextInt(members[group].size) == 0) {
- scores[group]
- } else {
- 1.0
- }
- }
-
- /**
- * Add an active group to this member.
- */
- internal fun addGroup(group: Int) {
- var groups = groups
- val groupsSize = groupsSize
- val pos = groups.binarySearch(group, toIndex = groupsSize)
-
- if (pos >= 0) {
- return
- }
-
- val idx = -pos - 1
-
- if (groups.size == groupsSize) {
- val newSize = groupsSize + (groupsSize shr 1)
- groups = groups.copyOf(newSize)
- this.groups = groups
- }
-
- groups.copyInto(groups, idx + 1, idx, groupsSize)
- groups[idx] = group
- this.groupsSize += 1
- }
-
- /**
- * Remove an active group from this member.
- */
- internal fun removeGroup(group: Int) {
- val groups = groups
- val groupsSize = groupsSize
- val pos = groups.binarySearch(group, toIndex = groupsSize)
-
- if (pos < 0) {
- return
- }
-
- groups.copyInto(groups, pos, pos + 1, groupsSize)
- this.groupsSize -= 1
- }
-
- override fun compareTo(other: VmInterferenceMember): Int {
- val cmp = model.hashCode().compareTo(other.model.hashCode())
- if (cmp != 0) {
- return cmp
- }
-
- return id.compareTo(other.id)
- }
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/interference/VmInterferenceModel.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/interference/VmInterferenceModel.kt
deleted file mode 100644
index 238bffc0..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/kernel/interference/VmInterferenceModel.kt
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.simulator.compute.kernel.interference
-
-import java.util.TreeMap
-import java.util.TreeSet
-
-/**
- * An interference model that models the resource interference between virtual machines on a host.
- *
- * @param members The target load of each group.
- * @param scores The performance score of each group.
- * @param members The members belonging to each group.
- * @param membership The identifier of each key.
- * @param size The number of groups.
- */
-public class VmInterferenceModel private constructor(
- private val idMapping: Map<String, Int>,
- private val members: Array<IntArray>,
- private val membership: Array<IntArray>,
- private val targets: DoubleArray,
- private val scores: DoubleArray,
- private val size: Int
-) {
- /**
- * Return the [VmInterferenceProfile] associated with the specified [id].
- *
- * @param id The identifier of the virtual machine.
- * @return A [VmInterferenceProfile] representing the virtual machine as part of interference model or `null` if
- * there is no profile for the virtual machine.
- */
- public fun getProfile(id: String): VmInterferenceProfile? {
- val intId = idMapping[id] ?: return null
- return VmInterferenceProfile(this, intId, membership[intId], members, targets, scores)
- }
-
- public companion object {
- /**
- * Construct a [Builder] instance.
- */
- @JvmStatic
- public fun builder(): Builder = Builder()
- }
-
- /**
- * Builder class for a [VmInterferenceModel]
- */
- public class Builder internal constructor() {
- /**
- * The target load of each group.
- */
- private var _targets = DoubleArray(INITIAL_CAPACITY) { Double.POSITIVE_INFINITY }
-
- /**
- * The performance score of each group.
- */
- private var _scores = DoubleArray(INITIAL_CAPACITY) { Double.POSITIVE_INFINITY }
-
- /**
- * The members of each group.
- */
- private var _members = ArrayList<Set<String>>(INITIAL_CAPACITY)
-
- /**
- * The mapping from member to group id.
- */
- private val ids = TreeSet<String>()
-
- /**
- * The number of groups in the model.
- */
- private var size = 0
-
- /**
- * Add the specified group to the model.
- */
- public fun addGroup(members: Set<String>, targetLoad: Double, score: Double): Builder {
- val size = size
-
- if (size == _targets.size) {
- grow()
- }
-
- _targets[size] = targetLoad
- _scores[size] = score
- _members.add(members)
- ids.addAll(members)
-
- this.size++
-
- return this
- }
-
- /**
- * Build the [VmInterferenceModel].
- */
- public fun build(): VmInterferenceModel {
- val size = size
- val targets = _targets
- val scores = _scores
- val members = _members
-
- val indices = IntArray(size) { it }
- indices.sortedWith(
- Comparator { l, r ->
- var cmp = targets[l].compareTo(targets[r]) // Order by target load
- if (cmp != 0) {
- return@Comparator cmp
- }
-
- cmp = scores[l].compareTo(scores[r]) // Higher penalty first (this means lower performance score first)
- if (cmp != 0) {
- cmp
- } else {
- l.compareTo(r)
- }
- }
- )
-
- val newTargets = DoubleArray(size)
- val newScores = DoubleArray(size)
- val newMembers = arrayOfNulls<IntArray>(size)
-
- var nextId = 0
- val idMapping = ids.associateWith { nextId++ }
- val membership = ids.associateWithTo(TreeMap()) { ArrayList<Int>() }
-
- for ((group, j) in indices.withIndex()) {
- newTargets[group] = targets[j]
- newScores[group] = scores[j]
- val groupMembers = members[j]
- val newGroupMembers = groupMembers.map { idMapping.getValue(it) }.toIntArray()
-
- newGroupMembers.sort()
- newMembers[group] = newGroupMembers
-
- for (member in groupMembers) {
- membership.getValue(member).add(group)
- }
- }
-
- @Suppress("UNCHECKED_CAST")
- return VmInterferenceModel(
- idMapping,
- newMembers as Array<IntArray>,
- membership.map { it.value.toIntArray() }.toTypedArray(),
- newTargets,
- newScores,
- size
- )
- }
-
- /**
- * Helper function to grow the capacity of the internal arrays.
- */
- private fun grow() {
- val oldSize = _targets.size
- val newSize = oldSize + (oldSize shr 1)
-
- _targets = _targets.copyOf(newSize)
- _scores = _scores.copyOf(newSize)
- }
-
- private companion object {
- /**
- * The initial capacity of the builder.
- */
- const val INITIAL_CAPACITY = 256
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/MachineModel.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/MachineModel.kt
deleted file mode 100644
index 22dcaef4..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/MachineModel.kt
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.simulator.compute.model
-
-/**
- * A description of the physical or virtual machine on which a bootable image runs.
- *
- * @property cpus The list of processing units available to the image.
- * @property memory The list of memory units available to the image.
- * @property net A list of network adapters available to the machine.
- * @property storage A list of storage devices available to the machine.
- */
-public data class MachineModel(
- public val cpus: List<ProcessingUnit>,
- public val memory: List<MemoryUnit>,
- public val net: List<NetworkAdapter> = emptyList(),
- public val storage: List<StorageDevice> = emptyList()
-) {
- /**
- * Optimize the [MachineModel] by merging all resources of the same type into a single resource with the combined
- * capacity. Such configurations can be simulated more efficiently by OpenDC.
- */
- public fun optimize(): MachineModel {
- val originalCpu = cpus[0]
- val freq = cpus.sumOf { it.frequency }
- val processingNode = originalCpu.node.copy(coreCount = 1)
- val processingUnits = listOf(originalCpu.copy(frequency = freq, node = processingNode))
-
- val memorySize = memory.sumOf { it.size }
- val memoryUnits = listOf(MemoryUnit("Generic", "Generic", 3200.0, memorySize))
-
- return MachineModel(processingUnits, memoryUnits)
- }
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/MemoryUnit.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/MemoryUnit.kt
deleted file mode 100644
index bcbde5b1..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/MemoryUnit.kt
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2020 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.simulator.compute.model
-
-/**
- * A memory unit of a compute resource, either virtual or physical.
- *
- * @property vendor The vendor string of the memory.
- * @property modelName The name of the memory model.
- * @property speed The access speed of the memory in MHz.
- * @property size The size of the memory unit in MBs.
- */
-public data class MemoryUnit(
- public val vendor: String,
- public val modelName: String,
- public val speed: Double,
- public val size: Long
-)
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/NetworkAdapter.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/NetworkAdapter.kt
deleted file mode 100644
index 46472144..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/NetworkAdapter.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.simulator.compute.model
-
-/**
- * A description of a network adapter that is
- *
- * @property vendor The vendor of the network adapter.
- * @property modelName The model name of the network adapter.
- * @property bandwidth The bandwidth of the network adapter in Mbps.
- */
-public data class NetworkAdapter(
- public val vendor: String,
- public val modelName: String,
- public val bandwidth: Double
-)
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/ProcessingNode.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/ProcessingNode.kt
deleted file mode 100644
index 58ed816c..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/ProcessingNode.kt
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2020 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.simulator.compute.model
-
-/**
- * A processing node/package/socket containing possibly several CPU cores.
- *
- * @property vendor The vendor string of the processor node.
- * @property modelName The name of the processor node.
- * @property arch The micro-architecture of the processor node.
- * @property coreCount The number of logical CPUs in the processor node.
- */
-public data class ProcessingNode(
- public val vendor: String,
- public val arch: String,
- public val modelName: String,
- public val coreCount: Int
-)
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/ProcessingUnit.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/ProcessingUnit.kt
deleted file mode 100644
index 415e95e6..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/ProcessingUnit.kt
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2020 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.simulator.compute.model
-
-/**
- * A single logical compute unit of processor node, either virtual or physical.
- *
- * @property node The processing node containing the CPU core.
- * @property id The identifier of the CPU core within the processing node.
- * @property frequency The clock rate of the CPU in MHz.
- */
-public data class ProcessingUnit(
- public val node: ProcessingNode,
- public val id: Int,
- public val frequency: Double
-)
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/StorageDevice.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/StorageDevice.kt
deleted file mode 100644
index 2621ad6d..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/model/StorageDevice.kt
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.simulator.compute.model
-
-/**
- * Model for a physical storage device attached to a machine.
- *
- * @property vendor The vendor of the storage device.
- * @property modelName The model name of the device.
- * @property capacity The capacity of the device.
- * @property readBandwidth The read bandwidth of the device in MBps.
- * @property writeBandwidth The write bandwidth of the device in MBps.
- */
-public data class StorageDevice(
- public val vendor: String,
- public val modelName: String,
- public val capacity: Double,
- public val readBandwidth: Double,
- public val writeBandwidth: Double
-)
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/AsymptoticPowerModel.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/AsymptoticPowerModel.kt
deleted file mode 100644
index 46c397fe..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/AsymptoticPowerModel.kt
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.simulator.compute.power
-
-import kotlin.math.E
-import kotlin.math.pow
-
-/**
- * The asymptotic power model partially adapted from GreenCloud.
- *
- * @param maxPower The maximum power draw of the server in W.
- * @param idlePower The power draw of the server at its lowest utilization level in W.
- * @param asymUtil A utilization level at which the server attains asymptotic,
- * i.e., close to linear power consumption versus the offered load.
- * For most of the CPUs,a is in [0.2, 0.5].
- * @param isDvfsEnabled A flag indicates whether DVFS is enabled.
- */
-public class AsymptoticPowerModel(
- private val maxPower: Double,
- private val idlePower: Double,
- private val asymUtil: Double,
- private val isDvfsEnabled: Boolean
-) : PowerModel {
- private val factor: Double = (maxPower - idlePower) / 100
-
- public override fun computePower(utilization: Double): Double =
- if (isDvfsEnabled) {
- idlePower + (factor * 100) / 2 * (1 + utilization.pow(3) - E.pow(-utilization.pow(3) / asymUtil))
- } else {
- idlePower + (factor * 100) / 2 * (1 + utilization - E.pow(-utilization / asymUtil))
- }
-
- override fun toString(): String = "AsymptoticPowerModel[max=$maxPower,idle=$idlePower,asymptotic=$asymUtil]"
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/CubicPowerModel.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/CubicPowerModel.kt
deleted file mode 100644
index 0d3bf6cc..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/CubicPowerModel.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.simulator.compute.power
-
-import kotlin.math.pow
-
-/**
- * The cubic power model partially adapted from CloudSim.
- *
- * @param maxPower The maximum power draw of the server in W.
- * @param idlePower The power draw of the server at its lowest utilization level in W.
- */
-public class CubicPowerModel(private val maxPower: Double, private val idlePower: Double) : PowerModel {
- private val factor: Double = (maxPower - idlePower) / 100.0.pow(3)
-
- public override fun computePower(utilization: Double): Double {
- return idlePower + factor * (utilization * 100).pow(3)
- }
-
- override fun toString(): String = "CubicPowerModel[max=$maxPower,idle=$idlePower]"
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/InterpolationPowerModel.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/InterpolationPowerModel.kt
deleted file mode 100644
index b17b87a9..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/InterpolationPowerModel.kt
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.simulator.compute.power
-
-import kotlin.math.ceil
-import kotlin.math.floor
-import kotlin.math.max
-import kotlin.math.min
-
-/**
- * The linear interpolation power model partially adapted from CloudSim.
- * This model is developed to adopt the <a href="http://www.spec.org/power_ssj2008/">SPECpower benchmark</a>.
- *
- * @param powerValues A [List] of average active power measured by the power analyzer(s) and accumulated by the
- * PTDaemon (Power and Temperature Daemon) for this measurement interval, displayed as watts (W).
- * @see <a href="http://www.spec.org/power_ssj2008/results/res2011q1/">Machines used in the SPEC benchmark</a>
- */
-public class InterpolationPowerModel(private val powerValues: List<Double>) : PowerModel {
- public override fun computePower(utilization: Double): Double {
- val clampedUtilization = min(1.0, max(0.0, utilization))
- val utilizationFlr = floor(clampedUtilization * 10).toInt()
- val utilizationCil = ceil(clampedUtilization * 10).toInt()
- val powerFlr: Double = getAveragePowerValue(utilizationFlr)
- val powerCil: Double = getAveragePowerValue(utilizationCil)
- val delta = (powerCil - powerFlr) / 10
-
- return if (utilization % 0.1 == 0.0) {
- getAveragePowerValue((clampedUtilization * 10).toInt())
- } else {
- powerFlr + delta * (clampedUtilization - utilizationFlr.toDouble() / 10) * 100
- }
- }
-
- override fun toString(): String = "InterpolationPowerModel[entries=${powerValues.size}]"
-
- /**
- * Gets the power consumption for a given utilization percentage.
- *
- * @param index the utilization percentage in the scale from [0 to 10],
- * where 10 means 100% of utilization.
- * @return the power consumption for the given utilization percentage
- */
- private fun getAveragePowerValue(index: Int): Double = powerValues[index]
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/LinearPowerModel.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/LinearPowerModel.kt
deleted file mode 100644
index dadc56ec..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/LinearPowerModel.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.simulator.compute.power
-
-/**
- * The linear power model partially adapted from CloudSim.
- *
- * @param maxPower The maximum power draw of the server in W.
- * @param idlePower The power draw of the server at its lowest utilization level in W.
- */
-public class LinearPowerModel(private val maxPower: Double, private val idlePower: Double) : PowerModel {
- /**
- * The linear interpolation factor of the model.
- */
- private val factor: Double = (maxPower - idlePower) / 100
-
- public override fun computePower(utilization: Double): Double {
- return idlePower + factor * utilization * 100
- }
-
- override fun toString(): String = "LinearPowerModel[max=$maxPower,idle=$idlePower]"
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/MsePowerModel.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/MsePowerModel.kt
deleted file mode 100644
index e9e72da8..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/MsePowerModel.kt
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.simulator.compute.power
-
-import kotlin.math.pow
-
-/**
- * The power model that minimizes the mean squared error (MSE)
- * to the actual power measurement by tuning the calibration parameter.
- * @see <a href="https://dl.acm.org/doi/abs/10.1145/1273440.1250665">
- * Fan et al., Power provisioning for a warehouse-sized computer, ACM SIGARCH'07</a>
- *
- * @param maxPower The maximum power draw of the server in W.
- * @param idlePower The power draw of the server at its lowest utilization level in W.
- * @param calibrationParam The parameter set to minimize the MSE.
- */
-public class MsePowerModel(
- private val maxPower: Double,
- private val idlePower: Double,
- private val calibrationParam: Double
-) : PowerModel {
- private val factor: Double = (maxPower - idlePower) / 100
-
- public override fun computePower(utilization: Double): Double {
- return idlePower + factor * (2 * utilization - utilization.pow(calibrationParam)) * 100
- }
-
- override fun toString(): String = "MsePowerModel[max=$maxPower,idle=$idlePower,MSE_param=$calibrationParam]"
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/PStatePowerDriver.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/PStatePowerDriver.kt
deleted file mode 100644
index ce7225d2..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/PStatePowerDriver.kt
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.simulator.compute.power
-
-import org.opendc.simulator.compute.SimMachine
-import org.opendc.simulator.compute.SimProcessingUnit
-import java.util.TreeMap
-import kotlin.math.max
-import kotlin.math.min
-
-/**
- * A [PowerDriver] that computes the power draw using multiple [PowerModel]s based on multiple frequency states.
- *
- * @param states A map describing the states of the driver.
- */
-public class PStatePowerDriver(states: Map<Double, PowerModel>) : PowerDriver {
- /**
- * The P-States defined by the user and ordered by key.
- */
- private val states: TreeMap<Double, PowerModel> = TreeMap(states)
-
- override fun createLogic(machine: SimMachine, cpus: List<SimProcessingUnit>): PowerDriver.Logic = object : PowerDriver.Logic {
- override fun computePower(): Double {
- var targetFreq = 0.0
- var totalSpeed = 0.0
-
- for (cpu in cpus) {
- targetFreq = max(cpu.capacity, targetFreq)
- totalSpeed += cpu.rate
- }
-
- val maxFreq = states.lastKey()
- val (actualFreq, model) = states.ceilingEntry(min(maxFreq, targetFreq))
- val utilization = totalSpeed / (actualFreq * cpus.size)
- return model.computePower(utilization)
- }
- }
-
- override fun toString(): String = "PStatePowerDriver[states=$states]"
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/PowerDriver.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/PowerDriver.kt
deleted file mode 100644
index 1a46dd4a..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/PowerDriver.kt
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.simulator.compute.power
-
-import org.opendc.simulator.compute.SimMachine
-import org.opendc.simulator.compute.SimProcessingUnit
-
-/**
- * A [PowerDriver] is responsible for tracking the power usage for a component of the machine.
- */
-public interface PowerDriver {
- /**
- * Create the driver logic for the specified [machine].
- */
- public fun createLogic(machine: SimMachine, cpus: List<SimProcessingUnit>): Logic
-
- /**
- * The logic of the power driver.
- */
- public interface Logic {
- /**
- * Compute the power consumption of the component.
- *
- * @return The power consumption of the component in W.
- */
- public fun computePower(): Double
- }
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/SimplePowerDriver.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/SimplePowerDriver.kt
deleted file mode 100644
index 34e91c35..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/SimplePowerDriver.kt
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.simulator.compute.power
-
-import org.opendc.simulator.compute.SimMachine
-import org.opendc.simulator.compute.SimProcessingUnit
-
-/**
- * A [PowerDriver] that computes the power consumption based on a single specified [power model][model].
- */
-public class SimplePowerDriver(private val model: PowerModel) : PowerDriver {
- override fun createLogic(machine: SimMachine, cpus: List<SimProcessingUnit>): PowerDriver.Logic = object : PowerDriver.Logic {
-
- override fun computePower(): Double {
- var targetFreq = 0.0
- var totalSpeed = 0.0
-
- for (cpu in cpus) {
- targetFreq += cpu.capacity
- totalSpeed += cpu.rate
- }
-
- return model.computePower(totalSpeed / targetFreq)
- }
- }
-
- override fun toString(): String = "SimplePowerDriver[model=$model]"
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/SqrtPowerModel.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/SqrtPowerModel.kt
deleted file mode 100644
index 0665dbd9..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/SqrtPowerModel.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.simulator.compute.power
-
-import kotlin.math.sqrt
-
-/**
- * The square root power model partially adapted from CloudSim.
- *
- * @param maxPower The maximum power draw of the server in W.
- * @param idlePower The power draw of the server at its lowest utilization level in W.
- */
-public class SqrtPowerModel(private val maxPower: Double, private val idlePower: Double) : PowerModel {
- private val factor: Double = (maxPower - idlePower) / sqrt(100.0)
-
- override fun computePower(utilization: Double): Double {
- return idlePower + factor * sqrt(utilization * 100)
- }
-
- override fun toString(): String = "SqrtPowerModel[max=$maxPower,idle=$idlePower]"
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/SquarePowerModel.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/SquarePowerModel.kt
deleted file mode 100644
index e4ae88a9..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/SquarePowerModel.kt
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.simulator.compute.power
-
-import kotlin.math.pow
-
-/**
- * The square power model partially adapted from CloudSim.
- *
- * @param maxPower The maximum power draw of the server in W.
- * @param idlePower The power draw of the server at its lowest utilization level in W.
- */
-public class SquarePowerModel(private val maxPower: Double, private val idlePower: Double) : PowerModel {
- private val factor: Double = (maxPower - idlePower) / 100.0.pow(2)
-
- override fun computePower(utilization: Double): Double {
- return idlePower + factor * (utilization * 100).pow(2)
- }
-
- override fun toString(): String = "SquarePowerModel[max=$maxPower,idle=$idlePower]"
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/ZeroIdlePowerDecorator.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/ZeroIdlePowerDecorator.kt
deleted file mode 100644
index 05ab4631..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/power/ZeroIdlePowerDecorator.kt
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.simulator.compute.power
-
-/**
- * A decorator for ignoring the idle power when computing energy consumption of components.
- *
- * @param delegate The [PowerModel] to delegate to.
- */
-public class ZeroIdlePowerDecorator(private val delegate: PowerModel) : PowerModel {
- override fun computePower(utilization: Double): Double {
- return if (utilization == 0.0) {
- 0.0
- } else {
- delegate.computePower(utilization)
- }
- }
-
- override fun toString(): String = "ZeroIdlePowerDecorator[delegate=$delegate]"
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimFlopsWorkload.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimFlopsWorkload.kt
deleted file mode 100644
index 726d1f56..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimFlopsWorkload.kt
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 2020 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.simulator.compute.workload
-
-import org.opendc.simulator.compute.SimMachineContext
-import org.opendc.simulator.flow.source.FixedFlowSource
-
-/**
- * A [SimWorkload] that models applications as a static number of floating point operations ([flops]) executed on
- * multiple cores of a compute resource.
- *
- * @property flops The number of floating point operations to perform for this task in MFLOPs.
- * @property utilization A model of the CPU utilization of the application.
- */
-public class SimFlopsWorkload(
- public val flops: Long,
- public val utilization: Double = 0.8
-) : SimWorkload {
- init {
- require(flops >= 0) { "Number of FLOPs must be positive" }
- require(utilization > 0.0 && utilization <= 1.0) { "Utilization must be in (0, 1]" }
- }
-
- override fun onStart(ctx: SimMachineContext) {
- val lifecycle = SimWorkloadLifecycle(ctx)
- for (cpu in ctx.cpus) {
- cpu.startConsumer(lifecycle.waitFor(FixedFlowSource(flops.toDouble() / ctx.cpus.size, utilization)))
- }
- }
-
- override fun onStop(ctx: SimMachineContext) {}
-
- override fun toString(): String = "SimFlopsWorkload(FLOPs=$flops,utilization=$utilization)"
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimRuntimeWorkload.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimRuntimeWorkload.kt
deleted file mode 100644
index 8a3f5f84..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimRuntimeWorkload.kt
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 2020 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.simulator.compute.workload
-
-import org.opendc.simulator.compute.SimMachineContext
-import org.opendc.simulator.flow.source.FixedFlowSource
-
-/**
- * A [SimWorkload] that models application execution as a single duration.
- *
- * @property duration The duration of the workload.
- * @property utilization The utilization of the application during runtime.
- */
-public class SimRuntimeWorkload(
- public val duration: Long,
- public val utilization: Double = 0.8
-) : SimWorkload {
- init {
- require(duration >= 0) { "Duration must be non-negative" }
- require(utilization > 0.0 && utilization <= 1.0) { "Utilization must be in (0, 1]" }
- }
-
- override fun onStart(ctx: SimMachineContext) {
- val lifecycle = SimWorkloadLifecycle(ctx)
- for (cpu in ctx.cpus) {
- val limit = cpu.capacity * utilization
- cpu.startConsumer(lifecycle.waitFor(FixedFlowSource((limit / 1000) * duration, utilization)))
- }
- }
-
- override fun onStop(ctx: SimMachineContext) {}
-
- override fun toString(): String = "SimRuntimeWorkload(duration=$duration,utilization=$utilization)"
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimTrace.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimTrace.kt
deleted file mode 100644
index db6a4629..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimTrace.kt
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.simulator.compute.workload
-
-import org.opendc.simulator.compute.model.ProcessingUnit
-import org.opendc.simulator.flow.FlowConnection
-import org.opendc.simulator.flow.FlowSource
-import kotlin.math.min
-
-/**
- * A workload trace that describes the resource utilization over time in a collection of [SimTraceFragment]s.
- *
- * @param usageCol The column containing the CPU usage of each fragment (in MHz).
- * @param deadlineCol The column containing the ending timestamp for each fragment (in epoch millis).
- * @param coresCol The column containing the utilized cores.
- * @param size The number of fragments in the trace.
- */
-public class SimTrace(
- private val usageCol: DoubleArray,
- private val deadlineCol: LongArray,
- private val coresCol: IntArray,
- private val size: Int
-) {
- init {
- require(size >= 0) { "Invalid trace size" }
- require(usageCol.size >= size) { "Invalid number of usage entries" }
- require(deadlineCol.size >= size) { "Invalid number of deadline entries" }
- require(coresCol.size >= size) { "Invalid number of core entries" }
- }
-
- public companion object {
- /**
- * Construct a [SimTrace] with the specified fragments.
- */
- @JvmStatic
- public fun ofFragments(fragments: List<SimTraceFragment>): SimTrace {
- val size = fragments.size
- val usageCol = DoubleArray(size)
- val deadlineCol = LongArray(size)
- val coresCol = IntArray(size)
-
- for (i in fragments.indices) {
- val fragment = fragments[i]
- usageCol[i] = fragment.usage
- deadlineCol[i] = fragment.timestamp + fragment.duration
- coresCol[i] = fragment.cores
- }
-
- return SimTrace(usageCol, deadlineCol, coresCol, size)
- }
-
- /**
- * Construct a [SimTrace] with the specified fragments.
- */
- @JvmStatic
- public fun ofFragments(vararg fragments: SimTraceFragment): SimTrace {
- val size = fragments.size
- val usageCol = DoubleArray(size)
- val deadlineCol = LongArray(size)
- val coresCol = IntArray(size)
-
- for (i in fragments.indices) {
- val fragment = fragments[i]
- usageCol[i] = fragment.usage
- deadlineCol[i] = fragment.timestamp + fragment.duration
- coresCol[i] = fragment.cores
- }
-
- return SimTrace(usageCol, deadlineCol, coresCol, size)
- }
-
- /**
- * Create a [SimTrace.Builder] instance.
- */
- @JvmStatic
- public fun builder(): Builder = Builder()
- }
-
- /**
- * Construct a new [FlowSource] for the specified [cpu].
- *
- * @param cpu The [ProcessingUnit] for which to create the source.
- * @param offset The time offset to use for the trace.
- */
- public fun newSource(cpu: ProcessingUnit, offset: Long): FlowSource {
- return CpuConsumer(cpu, offset, usageCol, deadlineCol, coresCol, size)
- }
-
- /**
- * A builder class for a [SimTrace].
- */
- public class Builder internal constructor() {
- /**
- * The columns of the trace.
- */
- private var usageCol: DoubleArray = DoubleArray(16)
- private var deadlineCol: LongArray = LongArray(16)
- private var coresCol: IntArray = IntArray(16)
-
- /**
- * The number of entries in the trace.
- */
- private var size = 0
-
- /**
- * Add the specified [SimTraceFragment] to the trace.
- */
- public fun add(fragment: SimTraceFragment) {
- add(fragment.timestamp + fragment.duration, fragment.usage, fragment.cores)
- }
-
- /**
- * Add a fragment to the trace.
- *
- * @param deadline Timestamp at which the fragment ends (in epoch millis).
- * @param usage CPU usage of this fragment.
- * @param cores Number of cores used.
- */
- public fun add(deadline: Long, usage: Double, cores: Int) {
- val size = size
-
- if (size == usageCol.size) {
- grow()
- }
-
- deadlineCol[size] = deadline
- usageCol[size] = usage
- coresCol[size] = cores
-
- this.size++
- }
-
- /**
- * Helper function to grow the capacity of the column arrays.
- */
- private fun grow() {
- val arraySize = usageCol.size
- val newSize = arraySize + (arraySize shr 1)
-
- usageCol = usageCol.copyOf(newSize)
- deadlineCol = deadlineCol.copyOf(newSize)
- coresCol = coresCol.copyOf(newSize)
- }
-
- /**
- * Construct the immutable [SimTrace].
- */
- public fun build(): SimTrace {
- return SimTrace(usageCol, deadlineCol, coresCol, size)
- }
- }
-
- /**
- * A CPU consumer for the trace workload.
- */
- private class CpuConsumer(
- cpu: ProcessingUnit,
- private val offset: Long,
- private val usageCol: DoubleArray,
- private val deadlineCol: LongArray,
- private val coresCol: IntArray,
- private val size: Int
- ) : FlowSource {
- private val id = cpu.id
- private val coreCount = cpu.node.coreCount
-
- /**
- * The index in the trace.
- */
- private var _idx = 0
-
- override fun onPull(conn: FlowConnection, now: Long): Long {
- val size = size
- val nowOffset = now - offset
-
- var idx = _idx
- val deadlines = deadlineCol
- var deadline = deadlines[idx]
-
- while (deadline <= nowOffset && ++idx < size) {
- deadline = deadlines[idx]
- }
-
- if (idx >= size) {
- conn.close()
- return Long.MAX_VALUE
- }
-
- _idx = idx
-
- val cores = min(coreCount, coresCol[idx])
- val usage = usageCol[idx]
-
- conn.push(if (id < cores) usage / cores else 0.0)
- return deadline - nowOffset
- }
- }
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimTraceFragment.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimTraceFragment.kt
deleted file mode 100644
index 5285847f..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimTraceFragment.kt
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.simulator.compute.workload
-
-/**
- * A fragment of the workload trace.
- *
- * @param timestamp The timestamp at which the fragment starts (in epoch millis).
- * @param duration The duration of the fragment (in milliseconds).
- * @param usage The CPU usage during the fragment (in MHz).
- * @param cores The amount of cores utilized during the fragment.
- */
-public data class SimTraceFragment(
- @JvmField val timestamp: Long,
- @JvmField val duration: Long,
- @JvmField val usage: Double,
- @JvmField val cores: Int
-)
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkload.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkload.kt
deleted file mode 100644
index ce04a790..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimTraceWorkload.kt
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (c) 2020 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.simulator.compute.workload
-
-import org.opendc.simulator.compute.SimMachineContext
-
-/**
- * A [SimWorkload] that replays a workload trace consisting of multiple fragments, each indicating the resource
- * consumption for some period of time.
- *
- * @param trace The trace of fragments to use.
- * @param offset The offset for the timestamps.
- */
-public class SimTraceWorkload(private val trace: SimTrace, private val offset: Long = 0L) : SimWorkload {
- override fun onStart(ctx: SimMachineContext) {
- val lifecycle = SimWorkloadLifecycle(ctx)
-
- for (cpu in ctx.cpus) {
- cpu.startConsumer(lifecycle.waitFor(trace.newSource(cpu.model, offset)))
- }
- }
-
- override fun onStop(ctx: SimMachineContext) {}
-
- override fun toString(): String = "SimTraceWorkload"
-}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimWorkloadLifecycle.kt b/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimWorkloadLifecycle.kt
deleted file mode 100644
index 46113bb0..00000000
--- a/opendc-simulator/opendc-simulator-compute/src/main/kotlin/org/opendc/simulator/compute/workload/SimWorkloadLifecycle.kt
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (c) 2021 AtLarge Research
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-package org.opendc.simulator.compute.workload
-
-import org.opendc.simulator.compute.SimMachineContext
-import org.opendc.simulator.flow.FlowConnection
-import org.opendc.simulator.flow.FlowSource
-
-/**
- * A helper class to manage the lifecycle of a [SimWorkload]
- */
-public class SimWorkloadLifecycle(private val ctx: SimMachineContext) {
- /**
- * The resource consumers which represent the lifecycle of the workload.
- */
- private val waiting = HashSet<Wrapper>()
-
- /**
- * Wait for the specified [source] to complete before ending the lifecycle of the workload.
- */
- public fun waitFor(source: FlowSource): FlowSource {
- val wrapper = Wrapper(source)
- waiting.add(wrapper)
- return wrapper
- }
-
- /**
- * Complete the specified [Wrapper].
- */
- private fun complete(wrapper: Wrapper) {
- if (waiting.remove(wrapper) && waiting.isEmpty()) {
- ctx.close()
- }
- }
-
- /**
- * A [FlowSource] that wraps [delegate] and informs [SimWorkloadLifecycle] that is has completed.
- */
- private inner class Wrapper(private val delegate: FlowSource) : FlowSource {
- override fun onStart(conn: FlowConnection, now: Long) {
- delegate.onStart(conn, now)
- }
-
- override fun onPull(conn: FlowConnection, now: Long): Long {
- return delegate.onPull(conn, now)
- }
-
- override fun onConverge(conn: FlowConnection, now: Long) {
- delegate.onConverge(conn, now)
- }
-
- override fun onStop(conn: FlowConnection, now: Long) {
- try {
- delegate.onStop(conn, now)
- } finally {
- complete(this)
- }
- }
-
- override fun toString(): String = "SimWorkloadLifecycle.Wrapper[delegate=$delegate]"
- }
-}