Skip to content

Commit 98841cd

Browse files
committed
docs: added documentation to calculatePoolUtil
Signed-off-by: MenD32 <[email protected]>
1 parent 1b0021f commit 98841cd

File tree

1 file changed

+26
-1
lines changed

1 file changed

+26
-1
lines changed

cluster-autoscaler/simulator/dynamicresources/utils/utilization.go

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,31 @@ func HighestDynamicResourceUtilization(nodeInfo *framework.NodeInfo) (v1.Resourc
7171
return highestResourceName, highestUtil, nil
7272
}
7373

74+
// calculatePoolUtil calculates the utilization of a ResourceSlice pool, accounting for both partitionable (shared counter) and atomic (non-partitionable) devices.
75+
// The calculation is comprised of steps:
76+
//
77+
// 1. Partitionable (Shared) Utilization:
78+
// Identifies the single highest utilization ratio across all shared counters
79+
// in the entire pool. This ratio represents the most constrained resource within the pool.
80+
// For example, if a GPU pool has shared counters for memory and compute cycles, and the memory's shared counter is at 80% utilization, and the compute cycles' counter is at 50%,
81+
// the partitionable utilization for the pool would be 80%.
82+
//
83+
// 2. Atomic (Non-partitionable) Utilization:
84+
// Calculated as the simple ratio of allocated devices to total devices for all devices
85+
// that do not support shared counters.
86+
//
87+
// 3. Final Weighted Average:
88+
// The result is a weighted average of the two types based on their population count in the pool.
89+
// This ensures that in mixed pools, the fullness of one resource type doesn't disproportionately
90+
// mask or amplify the state of the other.
91+
//
92+
// Example (3 total devices: 2 atomic, 1 partitionable):
93+
// - 2 atomic allocated, partitionable at 0% util:
94+
// Result: (1.0 * 2/3) + (0.0 * 1/3) = 66.6%
95+
// - 0 atomic allocated, partitionable at 100% util:
96+
// Result: (0.0 * 2/3) + (1.0 * 1/3) = 33.3%
97+
// - 1 atomic allocated, partitionable at 50% util:
98+
// Result: (0.5 * 2/3) + (0.5 * 1/3) = 50%
7499
func calculatePoolUtil(unallocated, allocated []resourceapi.Device, resourceSlices []*resourceapi.ResourceSlice) float64 {
75100
totalConsumedCounters := map[string]map[string]resource.Quantity{}
76101
for _, resourceSlice := range resourceSlices {
@@ -129,7 +154,7 @@ func calculatePoolUtil(unallocated, allocated []resourceapi.Device, resourceSlic
129154
var totalUniqueDevices float64 = uniquePartitionableDevicesCount + float64(devicesWithoutCounters)
130155
var partitionableDevicesUtilizationWeight float64 = uniquePartitionableDevicesCount / totalUniqueDevices
131156
var nonPartitionableDevicesUtilizationWeight float64 = 1 - partitionableDevicesUtilizationWeight
132-
// when a pool has both atomic and partitionable devices, we sum their utilizations since they are mutually exclusive
157+
// when a pool has both atomic and partitionable devices, we sum their utilizations since they are mutually exclusive (a partitionable device can't be allocated as an atomic device and vice versa).
133158
return partitionableUtilization*partitionableDevicesUtilizationWeight + atomicDevicesUtilization*nonPartitionableDevicesUtilizationWeight
134159
}
135160

0 commit comments

Comments
 (0)