summaryrefslogtreecommitdiff
path: root/opendc-simulator/opendc-simulator-compute/src/main
diff options
context:
space:
mode:
authorNiels Thiele <noleu66@posteo.net>2025-07-15 11:29:47 +0200
committerGitHub <noreply@github.com>2025-07-15 11:29:47 +0200
commitb2dc97dc84f56174ede9f273999ade2ed059d431 (patch)
tree1b5d6d775890375f46b533c7aa78e492a88afc3f /opendc-simulator/opendc-simulator-compute/src/main
parent0203254b709614fa732c114aa25916f61b8b3275 (diff)
multi gpu support (#351)
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/machine/SimMachine.java32
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/models/MachineModel.java14
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/SimPsu.java149
-rw-r--r--opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/VirtualMachine.java66
4 files changed, 159 insertions, 102 deletions
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/machine/SimMachine.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/machine/SimMachine.java
index 8792552e..c9e3ab8c 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/machine/SimMachine.java
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/machine/SimMachine.java
@@ -211,27 +211,43 @@ public class SimMachine {
ResourceType.CPU,
new ArrayList<>(List.of(new SimCpu(engine, this.machineModel.getCpuModel(), cpuPowerModel, 0))));
- new FlowEdge((FlowConsumer) this.computeResources.get(ResourceType.CPU).getFirst(), this.psu);
+ // Connect the CPU to the PSU
+ new FlowEdge(
+ (FlowConsumer) this.computeResources.get(ResourceType.CPU).getFirst(),
+ this.psu,
+ ResourceType.POWER,
+ 0,
+ -1);
// Create a FlowDistributor and add the cpu as supplier
this.distributors.put(ResourceType.CPU, new FlowDistributor(engine));
- new FlowEdge(this.distributors.get(ResourceType.CPU), (FlowSupplier)
- this.computeResources.get(ResourceType.CPU).getFirst());
+ new FlowEdge(
+ this.distributors.get(ResourceType.CPU),
+ (FlowSupplier) this.computeResources.get(ResourceType.CPU).getFirst(),
+ ResourceType.CPU,
+ -1,
+ 0);
// TODO: include memory as flow node
this.memory = new Memory(engine, this.machineModel.getMemory());
if (this.availableResources.contains(ResourceType.GPU)) {
this.distributors.put(ResourceType.GPU, new FlowDistributor(engine));
- short i = 0;
ArrayList<ComputeResource> gpus = new ArrayList<>();
for (GpuModel gpuModel : machineModel.getGpuModels()) {
- SimGpu gpu = new SimGpu(engine, gpuModel, gpuPowerModel, i);
+ // create a new GPU
+ SimGpu gpu = new SimGpu(engine, gpuModel, gpuPowerModel, gpuModel.getId());
gpus.add(gpu);
- // suspends here without the distributor
- new FlowEdge(this.distributors.get(ResourceType.GPU), gpu);
- new FlowEdge(gpu, this.psu);
+ // Connect the GPU to the distributor
+ new FlowEdge(
+ this.distributors.get(ResourceType.GPU),
+ gpu,
+ ResourceType.GPU,
+ gpuModel.getId(),
+ gpuModel.getId());
+ // Connect the GPU to the PSU
+ new FlowEdge(gpu, this.psu, ResourceType.POWER, gpuModel.getId(), gpuModel.getId());
}
this.computeResources.put(ResourceType.GPU, gpus);
}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/models/MachineModel.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/models/MachineModel.java
index 874194f6..e11d9cf2 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/models/MachineModel.java
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/models/MachineModel.java
@@ -35,7 +35,6 @@ import org.opendc.simulator.engine.graph.distributionPolicies.DistributionPolicy
public final class MachineModel {
private final CpuModel cpuModel;
private final MemoryUnit memory;
- // private final List<GpuModel> gpuModels = new ArrayList<>(); // TODO: Implement multi GPU support
private final List<GpuModel> gpuModels;
private final DistributionPolicy cpuDistributionStrategy;
private final DistributionPolicy gpuDistributionPolicy;
@@ -58,19 +57,8 @@ public final class MachineModel {
this.gpuDistributionPolicy = gpuDistributionPolicy;
this.availableResources.add(ResourceType.CPU);
// TODO: Add Memory
- // this.usedResources.add(ResourceType.Memory);
if (gpuModels != null && !gpuModels.isEmpty()) {
- // this.gpuModels = gpuModels;
- this.gpuModels = new ArrayList<>();
- this.gpuModels.add(new GpuModel(
- 0,
- gpuModels.getFirst().getCoreCount() * gpuModels.size(), // merges multiple GPUs into one
- gpuModels.getFirst().getCoreSpeed(),
- gpuModels.getFirst().getMemoryBandwidth(),
- gpuModels.getFirst().getMemorySize() * gpuModels.size(), // merges multiple GPUs into one
- gpuModels.getFirst().getVendor(),
- gpuModels.getFirst().getModelName(),
- gpuModels.getFirst().getArchitecture()));
+ this.gpuModels = gpuModels;
this.availableResources.add(ResourceType.GPU);
} else {
this.gpuModels = new ArrayList<>();
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/SimPsu.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/SimPsu.java
index 1ea7c570..f40f4fec 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/SimPsu.java
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/power/SimPsu.java
@@ -43,11 +43,14 @@ public final class SimPsu extends FlowNode implements FlowSupplier, FlowConsumer
private static final Logger LOGGER = LoggerFactory.getLogger(SimPsu.class);
private long lastUpdate;
- private final HashMap<ResourceType, ArrayList<Double>> powerDemandsPerResource = new HashMap<>();
- private final HashMap<ResourceType, ArrayList<Double>> powerSuppliedPerResource = new HashMap<>();
+ private final HashMap<ResourceType, HashMap<Integer, Double>> powerDemandsPerResource = new HashMap<>();
+ private final HashMap<ResourceType, HashMap<Integer, Double>> powerSuppliedPerResource = new HashMap<>();
+
+ private double totalPowerDemand = 0.0;
+ private double totalPowerSupplied = 0.0;
private double totalEnergyUsage = 0.0;
- private final HashMap<ResourceType, ArrayList<FlowEdge>> resourceEdges = new HashMap<>();
+ private final HashMap<ResourceType, HashMap<Integer, FlowEdge>> resourceEdges = new HashMap<>();
private FlowEdge powerSupplyEdge;
private final double capacity = Long.MAX_VALUE;
@@ -72,28 +75,51 @@ public final class SimPsu extends FlowNode implements FlowSupplier, FlowConsumer
* This method provides access to the power consumption of the machine before PSU losses are applied.
*/
public double getPowerDemand() {
- return this.powerDemandsPerResource.values().stream()
- .flatMap(List::stream)
- .findFirst()
- .orElse(0.0);
+ return this.totalPowerDemand;
}
+ /**
+ * Return the power demand of the machine (in W) measured in the PSU for a specific resource type.
+ * <p>
+ * This method provides access to the power consumption of the machine before PSU losses are applied.
+ */
public double getPowerDemand(ResourceType resourceType) {
- return this.powerDemandsPerResource.get(resourceType).getFirst();
+ // return this.powerDemandsPerResource.get(resourceType).stream().mapToDouble(Double::doubleValue).sum();
+ return this.powerDemandsPerResource.get(resourceType).values().stream()
+ .mapToDouble(Double::doubleValue)
+ .sum();
+ }
+
+ /**
+ * Return the power demand of the machine (in W) measured in the PSU for a specific resource type for a specific resource.
+ * <p>
+ * This method provides access to the power consumption of the machine before PSU losses are applied.
+ */
+ public double getPowerDemand(ResourceType resourceType, int id) {
+ return this.powerDemandsPerResource.get(resourceType).get(id);
}
/**
* Return the instantaneous power usage of the machine (in W) measured at the InPort of the power supply.
*/
public double getPowerDraw() {
- return this.powerSuppliedPerResource.values().stream()
- .flatMap(List::stream)
- .findFirst()
- .orElse(0.0);
+ return this.totalPowerSupplied;
}
+ /**
+ * Return the instantaneous power usage of the machine (in W) measured at the InPort of the power supply for a specific resource type.
+ */
public double getPowerDraw(ResourceType resourceType) {
- return this.powerSuppliedPerResource.get(resourceType).getFirst();
+ return this.powerSuppliedPerResource.get(resourceType).values().stream()
+ .mapToDouble(Double::doubleValue)
+ .sum();
+ }
+
+ /**
+ * Return the instantaneous power usage of the machine (in W) measured at the InPort of the power supply for a specific resource type for a specific resource.
+ */
+ public double getPowerDraw(ResourceType resourceType, int id) {
+ return this.powerSuppliedPerResource.get(resourceType).get(id);
}
/**
@@ -127,16 +153,22 @@ public final class SimPsu extends FlowNode implements FlowSupplier, FlowConsumer
public long onUpdate(long now) {
updateCounters();
for (ResourceType resourceType : this.resourceEdges.keySet()) {
- ArrayList<FlowEdge> edges = this.resourceEdges.get(resourceType);
+ HashMap<Integer, FlowEdge> edges = this.resourceEdges.get(resourceType);
if (edges != null && !edges.isEmpty()) {
- double powerSupply =
- this.powerDemandsPerResource.get(resourceType).getFirst();
- double powerSupplied =
- this.powerSuppliedPerResource.get(resourceType).getFirst();
-
- if (powerSupply != powerSupplied) {
- for (FlowEdge edge : edges) {
- edge.pushSupply(powerSupply);
+ for (FlowEdge edge : edges.values()) {
+ // If the edge is null, it means that the edge has been removed -> no update is needed
+ if (edge == null) {
+ continue;
+ }
+
+ int consumerIndex = edge.getConsumerIndex() == -1 ? 0 : edge.getConsumerIndex();
+ double powerDemand =
+ this.powerDemandsPerResource.get(resourceType).get(consumerIndex);
+ double powerSupplied =
+ this.powerSuppliedPerResource.get(resourceType).get(consumerIndex);
+
+ if (powerDemand != powerSupplied) {
+ edge.pushSupply(powerDemand);
}
}
}
@@ -159,7 +191,8 @@ public final class SimPsu extends FlowNode implements FlowSupplier, FlowConsumer
long duration = now - lastUpdate;
if (duration > 0) {
for (ResourceType resourceType : this.powerSuppliedPerResource.keySet()) {
- for (double powerSupplied : this.powerSuppliedPerResource.get(resourceType)) {
+ for (double powerSupplied :
+ this.powerSuppliedPerResource.get(resourceType).values()) {
this.totalEnergyUsage += (powerSupplied * duration * 0.001);
}
}
@@ -171,17 +204,8 @@ public final class SimPsu extends FlowNode implements FlowSupplier, FlowConsumer
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@Override
- public void pushOutgoingDemand(FlowEdge supplierEdge, double newDemand, ResourceType resourceType) {
- this.powerDemandsPerResource.put(resourceType, new ArrayList<>(List.of(newDemand)));
- powerSupplyEdge.pushDemand(newDemand);
- }
-
- @Override
public void pushOutgoingDemand(FlowEdge supplierEdge, double newDemand) {
- double totalDemand = this.powerDemandsPerResource.values().stream()
- .flatMap(List::stream)
- .reduce(0.0, Double::sum);
- this.powerSupplyEdge.pushDemand(totalDemand);
+ this.powerSupplyEdge.pushDemand(newDemand);
}
@Override
@@ -191,7 +215,13 @@ public final class SimPsu extends FlowNode implements FlowSupplier, FlowConsumer
@Override
public void pushOutgoingSupply(FlowEdge consumerEdge, double newSupply, ResourceType resourceType) {
- this.powerSuppliedPerResource.put(resourceType, new ArrayList<>(List.of(newSupply)));
+ int consumerIndex = consumerEdge.getConsumerIndex() == -1 ? 0 : consumerEdge.getConsumerIndex();
+
+ double previousSupply = this.powerSuppliedPerResource.get(resourceType).get(consumerIndex);
+ this.totalPowerSupplied += newSupply - previousSupply;
+
+ this.powerSuppliedPerResource.get(resourceType).put(consumerIndex, newSupply);
+
consumerEdge.pushSupply(newSupply, false, resourceType);
}
@@ -203,18 +233,29 @@ public final class SimPsu extends FlowNode implements FlowSupplier, FlowConsumer
@Override
public void handleIncomingDemand(FlowEdge consumerEdge, double newPowerDemand, ResourceType resourceType) {
updateCounters();
- this.powerDemandsPerResource.put(resourceType, new ArrayList<>(List.of(newPowerDemand)));
+ int consumerIndex = consumerEdge.getConsumerIndex() == -1 ? 0 : consumerEdge.getConsumerIndex();
+
+ double previousPowerDemand =
+ this.powerDemandsPerResource.get(resourceType).get(consumerIndex);
+ this.totalPowerDemand += newPowerDemand - previousPowerDemand;
- pushOutgoingDemand(this.powerSupplyEdge, newPowerDemand);
+ this.powerDemandsPerResource.get(resourceType).put(consumerIndex, newPowerDemand);
+
+ pushOutgoingDemand(this.powerSupplyEdge, totalPowerDemand);
}
@Override
public void handleIncomingSupply(FlowEdge supplierEdge, double newSupply) {
updateCounters();
for (ResourceType resourceType : this.resourceEdges.keySet()) {
- for (FlowEdge edge : this.resourceEdges.get(resourceType)) {
+ for (FlowEdge edge : this.resourceEdges.get(resourceType).values()) {
+ // If the edge is null, it means that the edge has been removed -> no update is needed
+ if (edge == null) {
+ continue;
+ }
+ int consumerIndex = edge.getConsumerIndex() == -1 ? 0 : edge.getConsumerIndex();
double outgoingSupply =
- Math.min(this.powerDemandsPerResource.get(resourceType).getFirst(), newSupply);
+ Math.min(this.powerDemandsPerResource.get(resourceType).get(consumerIndex), newSupply);
pushOutgoingSupply(edge, outgoingSupply, resourceType);
}
}
@@ -222,10 +263,19 @@ public final class SimPsu extends FlowNode implements FlowSupplier, FlowConsumer
@Override
public void addConsumerEdge(FlowEdge consumerEdge) {
+
ResourceType consumerResourceType = consumerEdge.getConsumerResourceType();
- this.resourceEdges.put(consumerResourceType, new ArrayList<>(List.of(consumerEdge)));
- this.powerDemandsPerResource.put(consumerResourceType, new ArrayList<>(List.of(0.0)));
- this.powerSuppliedPerResource.put(consumerResourceType, new ArrayList<>(List.of(0.0)));
+ int consumerIndex = consumerEdge.getConsumerIndex() == -1 ? 0 : consumerEdge.getConsumerIndex();
+
+ if (!this.resourceEdges.containsKey(consumerResourceType)) {
+ this.resourceEdges.put(consumerResourceType, new HashMap<>());
+ this.powerDemandsPerResource.put(consumerResourceType, new HashMap<>());
+ this.powerSuppliedPerResource.put(consumerResourceType, new HashMap<>());
+ }
+
+ this.resourceEdges.get(consumerResourceType).put(consumerIndex, consumerEdge);
+ this.powerDemandsPerResource.get(consumerResourceType).put(consumerIndex, 0.0);
+ this.powerSuppliedPerResource.get(consumerResourceType).put(consumerIndex, 0.0);
}
@Override
@@ -236,10 +286,18 @@ public final class SimPsu extends FlowNode implements FlowSupplier, FlowConsumer
@Override
public void removeConsumerEdge(FlowEdge consumerEdge) {
ResourceType resourceType = consumerEdge.getConsumerResourceType();
+ int consumerIndex = consumerEdge.getConsumerIndex() == -1 ? 0 : consumerEdge.getConsumerIndex();
+
if (this.resourceEdges.containsKey(resourceType)) {
- this.resourceEdges.remove(resourceType);
- this.powerDemandsPerResource.remove(resourceType);
- this.powerSuppliedPerResource.remove(resourceType);
+ this.resourceEdges.get(resourceType).put(consumerIndex, null);
+
+ this.totalPowerDemand -=
+ this.powerDemandsPerResource.get(resourceType).get(consumerIndex);
+ this.powerDemandsPerResource.get(resourceType).put(consumerIndex, 0.0);
+
+ this.totalPowerSupplied -=
+ this.powerSuppliedPerResource.get(resourceType).get(consumerIndex);
+ this.powerSuppliedPerResource.get(resourceType).put(consumerIndex, 0.0);
}
}
@@ -252,7 +310,8 @@ public final class SimPsu extends FlowNode implements FlowSupplier, FlowConsumer
public Map<FlowEdge.NodeType, List<FlowEdge>> getConnectedEdges() {
List<FlowEdge> supplyingEdges = new ArrayList<>();
for (ResourceType resourceType : this.resourceEdges.keySet()) {
- List<FlowEdge> edges = this.resourceEdges.get(resourceType);
+ List<FlowEdge> edges =
+ this.resourceEdges.get(resourceType).values().stream().toList();
if (edges != null && !edges.isEmpty()) {
supplyingEdges.addAll(edges);
}
diff --git a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/VirtualMachine.java b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/VirtualMachine.java
index 622d2b89..8922a97d 100644
--- a/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/VirtualMachine.java
+++ b/opendc-simulator/opendc-simulator-compute/src/main/java/org/opendc/simulator/compute/workload/VirtualMachine.java
@@ -56,7 +56,7 @@ public final class VirtualMachine extends SimWorkload implements FlowSupplier {
private final Hashtable<ResourceType, Double> resourceCapacities = new Hashtable<>();
private final Hashtable<ResourceType, Double> resourceTimeScalingFactor = new Hashtable<>(); // formerly known as d
private final Hashtable<ResourceType, FlowEdge> distributorEdges = new Hashtable<>();
- private final Hashtable<ResourceType, List<PerformanceCounters>> resourcePerformanceCounters = new Hashtable<>();
+ private final Hashtable<ResourceType, PerformanceCounters> resourcePerformanceCounters = new Hashtable<>();
private final long checkpointInterval;
private final long checkpointDuration;
@@ -108,21 +108,11 @@ public final class VirtualMachine extends SimWorkload implements FlowSupplier {
}
public PerformanceCounters getCpuPerformanceCounters() {
- return this.resourcePerformanceCounters.get(ResourceType.CPU).getFirst();
+ return this.resourcePerformanceCounters.get(ResourceType.CPU);
}
- public List<PerformanceCounters> getGpuPerformanceCounters() {
- return this.resourcePerformanceCounters.get(ResourceType.GPU) != null
- ? this.resourcePerformanceCounters.get(ResourceType.GPU)
- : new ArrayList<>();
- }
-
- public PerformanceCounters getGpuPerformanceCounters(int gpuId) {
- List<PerformanceCounters> gpuPerformanceCounters = this.resourcePerformanceCounters.get(ResourceType.GPU);
- if (gpuId < 0 || gpuId >= gpuPerformanceCounters.size()) {
- throw new IndexOutOfBoundsException("No such GPU id: " + gpuId);
- }
- return gpuPerformanceCounters.get(gpuId);
+ public PerformanceCounters getGpuPerformanceCounters() {
+ return this.resourcePerformanceCounters.get(ResourceType.GPU);
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -171,13 +161,9 @@ public final class VirtualMachine extends SimWorkload implements FlowSupplier {
this.resourceCapacities.put(resourceType, resources.getFirst().getCapacity());
- ArrayList<PerformanceCounters> performanceCounters = new ArrayList<>();
-
- for (ComputeResource resource : resources) {
- performanceCounters.add(new PerformanceCounters());
- this.resourceTimeScalingFactor.put(resourceType, 1.0 / resource.getCapacity());
- }
- this.resourcePerformanceCounters.put(resourceType, performanceCounters);
+ this.resourceTimeScalingFactor.put(
+ resourceType, 1.0 / resources.getFirst().getCapacity());
+ this.resourcePerformanceCounters.put(resourceType, new PerformanceCounters());
this.resourceDemands.put(resourceType, 0.0);
this.resourceSupplies.put(resourceType, 0.0);
}
@@ -225,21 +211,24 @@ public final class VirtualMachine extends SimWorkload implements FlowSupplier {
for (ResourceType resourceType : this.availableResources) {
int i = 0;
final double factor = this.resourceTimeScalingFactor.get(resourceType) * delta;
- for (PerformanceCounters performanceCounter : this.resourcePerformanceCounters.get(resourceType)) {
- if (delta > 0) {
- performanceCounter.addActiveTime(Math.round(this.resourceSupplies.get(resourceType) * factor));
- performanceCounter.setIdleTime(Math.round(
- (this.resourceCapacities.get(resourceType) - this.resourceSupplies.get(resourceType))
- * factor));
- performanceCounter.addStealTime(Math.round(
- (this.resourceDemands.get(resourceType) - this.resourceSupplies.get(resourceType))
- * factor));
- }
- performanceCounter.setDemand(this.resourceDemands.get(resourceType));
- performanceCounter.setSupply(this.resourceSupplies.get(resourceType));
- performanceCounter.setCapacity(this.resourceCapacities.get(resourceType));
- i++;
+ if (delta > 0) {
+ this.resourcePerformanceCounters
+ .get(resourceType)
+ .addActiveTime(Math.round(this.resourceSupplies.get(resourceType) * factor));
+ this.resourcePerformanceCounters
+ .get(resourceType)
+ .setIdleTime(Math.round(
+ (this.resourceCapacities.get(resourceType) - this.resourceSupplies.get(resourceType))
+ * factor));
+ this.resourcePerformanceCounters
+ .get(resourceType)
+ .addStealTime(Math.round(
+ (this.resourceDemands.get(resourceType) - this.resourceSupplies.get(resourceType))
+ * factor));
}
+ this.resourcePerformanceCounters.get(resourceType).setDemand(this.resourceDemands.get(resourceType));
+ this.resourcePerformanceCounters.get(resourceType).setSupply(this.resourceSupplies.get(resourceType));
+ this.resourcePerformanceCounters.get(resourceType).setCapacity(this.resourceCapacities.get(resourceType));
}
}
@@ -317,7 +306,12 @@ public final class VirtualMachine extends SimWorkload implements FlowSupplier {
@Override
public void addSupplierEdge(FlowEdge supplierEdge) {
ResourceType resourceType = supplierEdge.getSupplierResourceType();
- this.resourceCapacities.put(resourceType, supplierEdge.getCapacity());
+ if (this.resourceCapacities.containsKey(resourceType) && this.resourceCapacities.get(resourceType) > 0) {
+ this.resourceCapacities.put(
+ resourceType, this.resourceCapacities.get(resourceType) + supplierEdge.getCapacity());
+ } else {
+ this.resourceCapacities.put(resourceType, supplierEdge.getCapacity());
+ }
this.distributorEdges.put(resourceType, supplierEdge);
}