From df1028c71cb6d50db886c8076c7139ec24feb6d7 Mon Sep 17 00:00:00 2001 From: Dante Niewenhuis Date: Mon, 3 Feb 2025 13:11:48 +0100 Subject: Added Batteries (#300) * Batteries are implemented. Small problem with the deletion when running larger workloads. Added mock files for the Battery implementation. Updated the Carbon Model to allow for multiple receivers of CarbonIntensity * Implemented batteries in OpenDC. * Spotless applied --- .../simulator/compute/power/CarbonModel.java | 28 ++- .../simulator/compute/power/CarbonReceiver.java | 32 +++ .../simulator/compute/power/SimPowerSource.java | 25 +- .../compute/power/batteries/BatteryAggregator.java | 173 ++++++++++++++ .../compute/power/batteries/BatteryState.java | 29 +++ .../compute/power/batteries/PowerSourceType.java | 28 +++ .../compute/power/batteries/SimBattery.java | 253 +++++++++++++++++++++ .../power/batteries/policy/BatteryPolicy.java | 107 +++++++++ .../policy/DoubleThresholdBatteryPolicy.java | 64 ++++++ .../policy/SingleThresholdBatteryPolicy.java | 63 +++++ .../compute/workload/trace/SimTraceWorkload.java | 2 + 11 files changed, 786 insertions(+), 18 deletions(-) create mode 100644 opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/CarbonReceiver.java create mode 100644 opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/BatteryAggregator.java create mode 100644 opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/BatteryState.java create mode 100644 opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/PowerSourceType.java create mode 100644 opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/SimBattery.java create mode 100644 opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/policy/BatteryPolicy.java create mode 100644 opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/policy/DoubleThresholdBatteryPolicy.java create mode 100644 opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/batteries/policy/SingleThresholdBatteryPolicy.java (limited to 'opendc-simulator/opendc-simulator-compute') 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 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 fragments; + private final List 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 carbonFragments, long startTime) { + public CarbonModel(FlowGraph parentGraph, List 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 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 incomingSupplies = new ArrayList<>(Arrays.asList(0.0, 0.0)); + private final ArrayList 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; -- cgit v1.2.3