diff options
| author | Niels Thiele <noleu66@posteo.net> | 2025-07-15 11:29:47 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-07-15 11:29:47 +0200 |
| commit | b2dc97dc84f56174ede9f273999ade2ed059d431 (patch) | |
| tree | 1b5d6d775890375f46b533c7aa78e492a88afc3f /opendc-simulator/opendc-simulator-compute/src | |
| parent | 0203254b709614fa732c114aa25916f61b8b3275 (diff) | |
multi gpu support (#351)
Diffstat (limited to 'opendc-simulator/opendc-simulator-compute/src')
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); } |
