summaryrefslogtreecommitdiff
path: root/opendc-simulator
diff options
context:
space:
mode:
Diffstat (limited to 'opendc-simulator')
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/CarbonModel.java28
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/CarbonReceiver.java32
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/SimPowerSource.java25
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/BatteryAggregator.java173
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/BatteryState.java29
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/PowerSourceType.java28
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/SimBattery.java253
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/policy/BatteryPolicy.java107
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/policy/DoubleThresholdBatteryPolicy.java64
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/policy/SingleThresholdBatteryPolicy.java63
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/trace/SimTraceWorkload.java2
-rw-r--r--opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/graph/FlowGraph.java4
12 files changed, 789 insertions, 19 deletions
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/CarbonModel.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/CarbonModel.java
index 91095c01..b6246fe9 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/CarbonModel.java
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/CarbonModel.java
@@ -22,6 +22,7 @@
package org.opendc.simulator.compute.power;
+import java.util.ArrayList;
import java.util.List;
import org.opendc.simulator.engine.graph.FlowGraph;
import org.opendc.simulator.engine.graph.FlowNode;
@@ -32,11 +33,11 @@ import org.opendc.simulator.engine.graph.FlowNode;
*/
public class CarbonModel extends FlowNode {
- private SimPowerSource powerSource;
+ private final ArrayList<CarbonReceiver> receivers = new ArrayList<>();
- private long startTime = 0L; // The absolute timestamp on which the workload started
+ private final long startTime; // The absolute timestamp on which the workload started
- private List<CarbonFragment> fragments;
+ private final List<CarbonFragment> fragments;
private CarbonFragment current_fragment;
private int fragment_index;
@@ -45,16 +46,13 @@ public class CarbonModel extends FlowNode {
* Construct a CarbonModel
*
* @param parentGraph The active FlowGraph which should be used to make the new FlowNode
- * @param powerSource The Power Source which should be updated with the carbon intensity
* @param carbonFragments A list of Carbon Fragments defining the carbon intensity at different time frames
* @param startTime The start time of the simulation. This is used to go from relative time (used by the clock)
* to absolute time (used by carbon fragments).
*/
- public CarbonModel(
- FlowGraph parentGraph, SimPowerSource powerSource, List<CarbonFragment> carbonFragments, long startTime) {
+ public CarbonModel(FlowGraph parentGraph, List<CarbonFragment> carbonFragments, long startTime) {
super(parentGraph);
- this.powerSource = powerSource;
this.startTime = startTime;
this.fragments = carbonFragments;
@@ -64,6 +62,10 @@ public class CarbonModel extends FlowNode {
}
public void close() {
+ for (CarbonReceiver receiver : receivers) {
+ receiver.removeCarbonModel(this);
+ }
+
this.closeNode();
}
@@ -114,6 +116,16 @@ public class CarbonModel extends FlowNode {
}
private void pushCarbonIntensity(double carbonIntensity) {
- this.powerSource.updateCarbonIntensity(carbonIntensity);
+ for (CarbonReceiver receiver : this.receivers) {
+ receiver.updateCarbonIntensity(carbonIntensity);
+ }
+ }
+
+ public void addReceiver(CarbonReceiver receiver) {
+ this.receivers.add(receiver);
+
+ receiver.setCarbonModel(this);
+
+ receiver.updateCarbonIntensity(this.current_fragment.getCarbonIntensity());
}
}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/CarbonReceiver.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/CarbonReceiver.java
new file mode 100644
index 00000000..b1a011e1
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/CarbonReceiver.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2025 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION 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;
+
+public interface CarbonReceiver {
+
+ public void updateCarbonIntensity(double carbonIntensity);
+
+ public void setCarbonModel(CarbonModel carbonModel);
+
+ public void removeCarbonModel(CarbonModel carbonModel);
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/SimPowerSource.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/SimPowerSource.java
index f68c008e..3bc5ba70 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/SimPowerSource.java
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/SimPowerSource.java
@@ -22,7 +22,6 @@
package org.opendc.simulator.compute.power;
-import java.util.List;
import org.opendc.simulator.compute.cpu.SimCpu;
import org.opendc.simulator.engine.graph.FlowEdge;
import org.opendc.simulator.engine.graph.FlowGraph;
@@ -32,7 +31,7 @@ import org.opendc.simulator.engine.graph.FlowSupplier;
/**
* A {@link SimPsu} implementation that estimates the power consumption based on CPU usage.
*/
-public final class SimPowerSource extends FlowNode implements FlowSupplier {
+public final class SimPowerSource extends FlowNode implements FlowSupplier, CarbonReceiver {
private long lastUpdate;
private double powerDemand = 0.0f;
@@ -42,10 +41,11 @@ public final class SimPowerSource extends FlowNode implements FlowSupplier {
private double carbonIntensity = 0.0f;
private double totalCarbonEmission = 0.0f;
- private CarbonModel carbonModel = null;
private FlowEdge distributorEdge;
- private double capacity = Long.MAX_VALUE;
+ private double capacity;
+
+ private CarbonModel carbonModel = null;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Basic Getters and Setters
@@ -100,21 +100,17 @@ public final class SimPowerSource extends FlowNode implements FlowSupplier {
// Constructors
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- public SimPowerSource(FlowGraph graph, double max_capacity, List<CarbonFragment> carbonFragments, long startTime) {
+ public SimPowerSource(FlowGraph graph, double max_capacity) {
super(graph);
this.capacity = max_capacity;
- if (carbonFragments != null) {
- this.carbonModel = new CarbonModel(graph, this, carbonFragments, startTime);
- }
lastUpdate = this.clock.millis();
}
public void close() {
if (this.carbonModel != null) {
this.carbonModel.close();
- this.carbonModel = null;
}
this.closeNode();
@@ -126,7 +122,6 @@ public final class SimPowerSource extends FlowNode implements FlowSupplier {
@Override
public long onUpdate(long now) {
-
return Long.MAX_VALUE;
}
@@ -189,4 +184,14 @@ public final class SimPowerSource extends FlowNode implements FlowSupplier {
this.updateCounters();
this.carbonIntensity = carbonIntensity;
}
+
+ @Override
+ public void setCarbonModel(CarbonModel carbonModel) {
+ this.carbonModel = carbonModel;
+ }
+
+ @Override
+ public void removeCarbonModel(CarbonModel carbonModel) {
+ this.carbonModel = null;
+ }
}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/BatteryAggregator.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/BatteryAggregator.java
new file mode 100644
index 00000000..14d15b17
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/BatteryAggregator.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2025 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION 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.batteries;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import org.opendc.simulator.engine.graph.FlowConsumer;
+import org.opendc.simulator.engine.graph.FlowDistributor;
+import org.opendc.simulator.engine.graph.FlowEdge;
+import org.opendc.simulator.engine.graph.FlowGraph;
+import org.opendc.simulator.engine.graph.FlowNode;
+import org.opendc.simulator.engine.graph.FlowSupplier;
+
+public class BatteryAggregator extends FlowNode implements FlowConsumer, FlowSupplier {
+
+ private FlowEdge batteryEdge;
+ private FlowEdge powerSourceEdge;
+ private FlowEdge hostEdge;
+
+ private PowerSourceType powerSourceType = PowerSourceType.PowerSource;
+
+ private double incomingDemand;
+ private double outgoingSupply;
+
+ private double incomingSupply;
+
+ private final ArrayList<Double> incomingSupplies = new ArrayList<>(Arrays.asList(0.0, 0.0));
+ private final ArrayList<Double> outgoingDemands = new ArrayList<>(Arrays.asList(0.0, 0.0));
+
+ private boolean outgoingDemandUpdateNeeded = false;
+
+ /**
+ * Construct a new {@link FlowNode} instance.
+ *
+ * @param parentGraph The {@link FlowGraph} this stage belongs to.
+ */
+ public BatteryAggregator(FlowGraph parentGraph, SimBattery battery, FlowDistributor powerSourceDistributor) {
+ super(parentGraph);
+
+ this.powerSourceEdge = parentGraph.addEdge(this, powerSourceDistributor);
+ this.powerSourceEdge.setSupplierIndex(0);
+ this.batteryEdge = parentGraph.addEdge(this, battery);
+ this.batteryEdge.setSupplierIndex(1);
+ }
+
+ public void close() {
+ if (this.batteryEdge == null) {
+ return;
+ }
+
+ this.batteryEdge = null;
+ this.powerSourceEdge = null;
+
+ this.closeNode();
+ }
+
+ @Override
+ public long onUpdate(long now) {
+
+ if (this.outgoingDemandUpdateNeeded) {
+
+ if (this.powerSourceType == PowerSourceType.PowerSource) {
+ this.pushOutgoingDemand(this.batteryEdge, 0.0f);
+ this.pushOutgoingDemand(this.powerSourceEdge, this.incomingDemand);
+ }
+
+ if (this.powerSourceType == PowerSourceType.Battery) {
+ this.pushOutgoingDemand(this.powerSourceEdge, 0.0f);
+ this.pushOutgoingDemand(this.batteryEdge, this.incomingDemand);
+ }
+
+ this.outgoingDemandUpdateNeeded = false;
+
+ this.invalidate();
+
+ return Long.MAX_VALUE;
+ }
+
+ if (this.hostEdge != null) {
+ this.pushOutgoingSupply(this.hostEdge, this.incomingSupply);
+ }
+
+ return Long.MAX_VALUE;
+ }
+
+ @Override
+ public void handleIncomingDemand(FlowEdge consumerEdge, double newDemand) {
+ this.incomingDemand = newDemand;
+
+ this.outgoingDemandUpdateNeeded = true;
+ this.invalidate();
+ }
+
+ @Override
+ public void handleIncomingSupply(FlowEdge supplierEdge, double newSupply) {
+ int supplier_id = supplierEdge.getSupplierIndex();
+
+ this.incomingSupply += newSupply - this.incomingSupplies.get(supplier_id);
+
+ this.incomingSupplies.set(supplier_id, newSupply);
+
+ this.invalidate();
+ }
+
+ @Override
+ public void pushOutgoingDemand(FlowEdge supplierEdge, double newDemand) {
+ supplierEdge.pushDemand(newDemand);
+ }
+
+ @Override
+ public void addSupplierEdge(FlowEdge supplierEdge) {}
+
+ @Override
+ public void removeSupplierEdge(FlowEdge supplierEdge) {
+ this.close();
+ }
+
+ @Override
+ public void pushOutgoingSupply(FlowEdge consumerEdge, double newSupply) {
+ consumerEdge.pushSupply(newSupply);
+ }
+
+ @Override
+ public void addConsumerEdge(FlowEdge consumerEdge) {
+ this.hostEdge = consumerEdge;
+ }
+
+ @Override
+ public void removeConsumerEdge(FlowEdge consumerEdge) {
+ this.close();
+ }
+
+ public PowerSourceType getPowerSourceType() {
+ return powerSourceType;
+ }
+
+ public void setPowerSourceType(PowerSourceType newPowerSourceType) {
+ if (this.powerSourceType == newPowerSourceType) {
+ return;
+ }
+
+ this.powerSourceType = newPowerSourceType;
+
+ this.outgoingDemandUpdateNeeded = true;
+
+ this.invalidate();
+ }
+
+ @Override
+ public double getCapacity() {
+ return 0;
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/BatteryState.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/BatteryState.java
new file mode 100644
index 00000000..0f010864
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/BatteryState.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2025 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION 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.batteries;
+
+public enum BatteryState {
+ Charging,
+ Idle,
+ Discharging
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/PowerSourceType.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/PowerSourceType.java
new file mode 100644
index 00000000..8e760444
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/PowerSourceType.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2025 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION 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.batteries;
+
+public enum PowerSourceType {
+ PowerSource,
+ Battery
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/SimBattery.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/SimBattery.java
new file mode 100644
index 00000000..ad7e09e3
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/SimBattery.java
@@ -0,0 +1,253 @@
+/*
+ * Copyright (c) 2025 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION 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.batteries;
+
+import org.opendc.simulator.compute.power.batteries.policy.BatteryPolicy;
+import org.opendc.simulator.engine.graph.FlowConsumer;
+import org.opendc.simulator.engine.graph.FlowEdge;
+import org.opendc.simulator.engine.graph.FlowGraph;
+import org.opendc.simulator.engine.graph.FlowNode;
+import org.opendc.simulator.engine.graph.FlowSupplier;
+
+public class SimBattery extends FlowNode implements FlowConsumer, FlowSupplier {
+
+ private final double capacity;
+ private double chargingSpeed;
+
+ private FlowEdge distributorEdge;
+ private FlowEdge aggregatorEdge;
+
+ private BatteryState batteryState = BatteryState.Idle;
+
+ private double charge;
+
+ private long lastUpdate;
+ private double incomingSupply;
+ private double incomingDemand;
+
+ private double outgoingDemand;
+ private double outgoingSupply;
+
+ public BatteryPolicy getBatteryPolicy() {
+ return batteryPolicy;
+ }
+
+ public void setBatteryPolicy(BatteryPolicy batteryPolicy) {
+ this.batteryPolicy = batteryPolicy;
+ }
+
+ private BatteryPolicy batteryPolicy;
+
+ public BatteryState getBatteryState() {
+ return batteryState;
+ }
+
+ public double getCharge() {
+ return charge;
+ }
+
+ public void setCharge(double charge) {
+ this.charge = charge;
+ }
+
+ @Override
+ public double getCapacity() {
+ return this.capacity;
+ }
+
+ public boolean isFull() {
+ return (this.charge >= this.capacity);
+ }
+ ;
+
+ public boolean isEmpty() {
+ return (this.charge <= 0.0);
+ }
+ ;
+
+ /**
+ * Construct a new {@link FlowNode} instance.
+ *
+ * @param parentGraph The {@link FlowGraph} this stage belongs to.
+ */
+ public SimBattery(FlowGraph parentGraph, double capacity, double chargingSpeed, double initialCharge) {
+ super(parentGraph);
+ this.capacity = capacity;
+ this.chargingSpeed = chargingSpeed;
+
+ this.charge = initialCharge;
+ }
+
+ public void close() {
+ if (this.distributorEdge == null) {
+ return;
+ }
+
+ this.distributorEdge = null;
+ this.aggregatorEdge = null;
+
+ this.closeNode();
+ }
+
+ @Override
+ public long onUpdate(long now) {
+
+ long passedTime = now - lastUpdate;
+ this.lastUpdate = now;
+
+ if (this.batteryState == BatteryState.Idle) {
+ return Long.MAX_VALUE;
+ }
+
+ this.updateCharge(passedTime);
+ long remainingTime = 0L;
+
+ if (this.batteryState == BatteryState.Charging) {
+ if (this.isFull()) {
+ this.batteryPolicy.invalidate();
+ return Long.MAX_VALUE;
+ }
+
+ remainingTime = this.calculateRemainingTime();
+ }
+
+ if (this.batteryState == BatteryState.Discharging) {
+ if (this.isEmpty()) {
+ this.batteryPolicy.invalidate();
+ return Long.MAX_VALUE;
+ }
+
+ this.pushOutgoingSupply(this.aggregatorEdge, this.incomingDemand);
+ remainingTime = this.calculateRemainingTime();
+ }
+
+ long nextUpdate = now + remainingTime;
+
+ if (nextUpdate < 0) {
+ nextUpdate = Long.MAX_VALUE;
+ }
+ return nextUpdate;
+ }
+
+ private long calculateRemainingTime() {
+ if ((this.batteryState == BatteryState.Charging) && (this.incomingSupply > 0.0)) {
+ double remainingCharge = this.capacity - this.charge;
+ return (long) Math.ceil((remainingCharge / this.incomingSupply) * 1000);
+ }
+
+ if ((this.batteryState == BatteryState.Discharging) && (this.outgoingSupply > 0.0)) {
+ return (long) Math.ceil((this.charge / this.outgoingSupply) * 1000);
+ }
+
+ return Long.MAX_VALUE;
+ }
+
+ private void updateCharge(long passedTime) {
+ if (this.batteryState == BatteryState.Charging) {
+ this.charge += this.incomingSupply * (passedTime / 1000.0);
+ }
+
+ if (this.batteryState == BatteryState.Discharging) {
+ this.charge -= this.outgoingSupply * (passedTime / 1000.0);
+ }
+ }
+
+ public void setBatteryState(BatteryState newBatteryState) {
+ if (newBatteryState == this.batteryState) {
+ return;
+ }
+
+ long now = this.clock.millis();
+ long passedTime = now - lastUpdate;
+
+ updateCharge(passedTime);
+
+ this.lastUpdate = now;
+
+ this.batteryState = newBatteryState;
+
+ if (this.batteryState == BatteryState.Idle) {
+ this.pushOutgoingDemand(this.distributorEdge, 0.0f);
+ this.pushOutgoingSupply(this.distributorEdge, 0.0f);
+ }
+
+ if (this.batteryState == BatteryState.Charging) {
+ this.pushOutgoingDemand(this.distributorEdge, this.chargingSpeed);
+ this.pushOutgoingSupply(this.aggregatorEdge, 0.0f);
+ }
+
+ if (this.batteryState == BatteryState.Discharging) {
+ this.pushOutgoingDemand(this.distributorEdge, 0.0f);
+ }
+
+ this.invalidate();
+ }
+
+ @Override
+ public void handleIncomingSupply(FlowEdge supplierEdge, double newSupply) {
+ this.incomingSupply = newSupply;
+
+ this.invalidate();
+ }
+
+ @Override
+ public void pushOutgoingDemand(FlowEdge supplierEdge, double newDemand) {
+ this.outgoingDemand = newDemand;
+
+ this.distributorEdge.pushDemand(newDemand);
+ }
+
+ @Override
+ public void addSupplierEdge(FlowEdge supplierEdge) {
+ this.distributorEdge = supplierEdge;
+ }
+
+ @Override
+ public void removeSupplierEdge(FlowEdge supplierEdge) {
+ this.close();
+ }
+
+ @Override
+ public void handleIncomingDemand(FlowEdge consumerEdge, double newDemand) {
+ this.incomingDemand = newDemand;
+
+ this.invalidate();
+ }
+
+ @Override
+ public void pushOutgoingSupply(FlowEdge consumerEdge, double newSupply) {
+ this.outgoingSupply = newSupply;
+
+ this.aggregatorEdge.pushSupply(newSupply);
+ }
+
+ @Override
+ public void addConsumerEdge(FlowEdge consumerEdge) {
+ this.aggregatorEdge = consumerEdge;
+ }
+
+ @Override
+ public void removeConsumerEdge(FlowEdge consumerEdge) {
+ this.close();
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/policy/BatteryPolicy.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/policy/BatteryPolicy.java
new file mode 100644
index 00000000..be2f49e0
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/policy/BatteryPolicy.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2025 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION 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.batteries.policy;
+
+import org.opendc.simulator.compute.power.CarbonModel;
+import org.opendc.simulator.compute.power.CarbonReceiver;
+import org.opendc.simulator.compute.power.batteries.BatteryAggregator;
+import org.opendc.simulator.compute.power.batteries.BatteryState;
+import org.opendc.simulator.compute.power.batteries.PowerSourceType;
+import org.opendc.simulator.compute.power.batteries.SimBattery;
+import org.opendc.simulator.engine.graph.FlowGraph;
+import org.opendc.simulator.engine.graph.FlowNode;
+
+public abstract class BatteryPolicy extends FlowNode implements CarbonReceiver {
+
+ protected final SimBattery battery;
+ protected final BatteryAggregator aggregator;
+
+ protected double carbonIntensity;
+
+ protected BatteryState batteryState = BatteryState.Idle;
+
+ /**
+ * Construct a new {@link FlowNode} instance.
+ *
+ * @param parentGraph The {@link FlowGraph} this stage belongs to.
+ */
+ public BatteryPolicy(FlowGraph parentGraph, SimBattery battery, BatteryAggregator aggregator) {
+ super(parentGraph);
+
+ this.battery = battery;
+ this.battery.setBatteryPolicy(this);
+
+ this.aggregator = aggregator;
+ }
+
+ public void close() {
+ this.closeNode();
+ }
+
+ @Override
+ public abstract long onUpdate(long now);
+
+ public void setBatteryState(BatteryState newBatteryState) {
+ if (newBatteryState == this.batteryState) {
+ return;
+ }
+
+ this.batteryState = newBatteryState;
+
+ if (newBatteryState == BatteryState.Charging) {
+ this.battery.setBatteryState(BatteryState.Charging);
+ this.aggregator.setPowerSourceType(PowerSourceType.PowerSource);
+ return;
+ }
+
+ if (newBatteryState == BatteryState.Idle) {
+ this.battery.setBatteryState(BatteryState.Idle);
+ this.aggregator.setPowerSourceType(PowerSourceType.PowerSource);
+ return;
+ }
+
+ if (newBatteryState == BatteryState.Discharging) {
+ this.battery.setBatteryState(BatteryState.Discharging);
+ this.aggregator.setPowerSourceType(PowerSourceType.Battery);
+ }
+ }
+
+ @Override
+ public void updateCarbonIntensity(double newCarbonIntensity) {
+ if (newCarbonIntensity == this.carbonIntensity) {
+ return;
+ }
+
+ this.carbonIntensity = newCarbonIntensity;
+
+ this.invalidate();
+ }
+
+ @Override
+ public void setCarbonModel(CarbonModel carbonModel) {}
+
+ @Override
+ public void removeCarbonModel(CarbonModel carbonModel) {
+ this.close();
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/policy/DoubleThresholdBatteryPolicy.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/policy/DoubleThresholdBatteryPolicy.java
new file mode 100644
index 00000000..18da75d0
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/policy/DoubleThresholdBatteryPolicy.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2025 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION 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.batteries.policy;
+
+import org.opendc.simulator.compute.power.batteries.BatteryAggregator;
+import org.opendc.simulator.compute.power.batteries.BatteryState;
+import org.opendc.simulator.compute.power.batteries.SimBattery;
+import org.opendc.simulator.engine.graph.FlowGraph;
+
+public class DoubleThresholdBatteryPolicy extends BatteryPolicy {
+
+ private final double carbonThreshold;
+
+ /**
+ *
+ * @param parentGraph The {@link FlowGraph} this stage belongs to.
+ * @param battery
+ * @param aggregator
+ * @param carbonThreshold
+ */
+ public DoubleThresholdBatteryPolicy(
+ FlowGraph parentGraph, SimBattery battery, BatteryAggregator aggregator, double carbonThreshold) {
+ super(parentGraph, battery, aggregator);
+
+ this.carbonThreshold = carbonThreshold;
+ }
+
+ @Override
+ public long onUpdate(long now) {
+
+ if (this.carbonIntensity >= this.carbonThreshold & !this.battery.isEmpty()) {
+ this.setBatteryState(BatteryState.Discharging);
+ return Long.MAX_VALUE;
+ }
+
+ if (this.carbonIntensity < this.carbonThreshold & !this.battery.isFull()) {
+ this.setBatteryState(BatteryState.Charging);
+ return Long.MAX_VALUE;
+ }
+
+ this.setBatteryState(BatteryState.Idle);
+ return Long.MAX_VALUE;
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/policy/SingleThresholdBatteryPolicy.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/policy/SingleThresholdBatteryPolicy.java
new file mode 100644
index 00000000..4d71c096
--- /dev/null
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/policy/SingleThresholdBatteryPolicy.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2025 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION 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.batteries.policy;
+
+import org.opendc.simulator.compute.power.batteries.BatteryAggregator;
+import org.opendc.simulator.compute.power.batteries.BatteryState;
+import org.opendc.simulator.compute.power.batteries.SimBattery;
+import org.opendc.simulator.engine.graph.FlowGraph;
+
+public class SingleThresholdBatteryPolicy extends BatteryPolicy {
+ private final double carbonThreshold;
+
+ /**
+ *
+ * @param parentGraph The {@link FlowGraph} this stage belongs to.
+ * @param battery
+ * @param aggregator
+ * @param carbonThreshold
+ */
+ public SingleThresholdBatteryPolicy(
+ FlowGraph parentGraph, SimBattery battery, BatteryAggregator aggregator, double carbonThreshold) {
+ super(parentGraph, battery, aggregator);
+
+ this.carbonThreshold = carbonThreshold;
+ }
+
+ @Override
+ public long onUpdate(long now) {
+
+ if (this.carbonIntensity >= this.carbonThreshold & !this.battery.isEmpty()) {
+ this.setBatteryState(BatteryState.Discharging);
+ return Long.MAX_VALUE;
+ }
+
+ if (this.carbonIntensity < this.carbonThreshold & !this.battery.isFull()) {
+ this.setBatteryState(BatteryState.Charging);
+ return Long.MAX_VALUE;
+ }
+
+ this.setBatteryState(BatteryState.Idle);
+ return Long.MAX_VALUE;
+ }
+}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/trace/SimTraceWorkload.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/trace/SimTraceWorkload.java
index 93733268..b6d939c9 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/trace/SimTraceWorkload.java
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/trace/SimTraceWorkload.java
@@ -155,6 +155,8 @@ public class SimTraceWorkload extends SimWorkload implements FlowConsumer {
return;
}
+ // TODO: Maybe move this to the end
+ // Currently stopWorkload is called twice
this.closeNode();
this.machineEdge = null;
diff --git a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/graph/FlowGraph.java b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/graph/FlowGraph.java
index 91662950..60d57785 100644
--- a/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/graph/FlowGraph.java
+++ b/opendc-simulator/opendc-simulator-flow/src/main/java/org/opendc/simulator/engine/graph/FlowGraph.java
@@ -76,7 +76,7 @@ public class FlowGraph {
/**
* Add an edge between the specified consumer and supplier in this graph.
*/
- public void addEdge(FlowConsumer flowConsumer, FlowSupplier flowSupplier) {
+ public FlowEdge addEdge(FlowConsumer flowConsumer, FlowSupplier flowSupplier) {
// Check if the consumer and supplier are both FlowNodes
if (!(flowConsumer instanceof FlowNode)) {
throw new IllegalArgumentException("Flow consumer is not a FlowNode");
@@ -99,6 +99,8 @@ public class FlowGraph {
nodeToEdge.get((FlowNode) flowConsumer).add(flowEdge);
nodeToEdge.get((FlowNode) flowSupplier).add(flowEdge);
+
+ return flowEdge;
}
public void removeEdge(FlowEdge flowEdge) {