Преглед изворни кода

fix: Preserve max usage values during allocation aggregation

When allocations are aggregated (combined via Add), the code was
setting RawAllocationOnly to nil, which discarded critical peak usage
metrics:
- CPUCoreUsageMax
- RAMBytesUsageMax
- GPUUsageMax

This caused massive discrepancies in integration tests comparing
Prometheus vs Allocation API results. For example:
- RAMUsageMax: Prometheus=1.24GB, API=139MB (89% difference)

The issue: The comment said "Any data that is in a raw allocation only
is not valid in any sort of cumulative Allocation" but this is wrong
for MAX values. Max values represent peak usage at a point in time.
When combining allocations, we need the HIGHEST peak among all
combined allocations, not nil.

Fix:
- When both allocations have RawAllocationOnly data, take the maximum
  of each max field (CPUCoreUsageMax, RAMBytesUsageMax, GPUUsageMax)
- When only one has data, preserve it
- This ensures aggregated allocations correctly report peak usage

This fixes the integration test failures where allocation API was
reporting ~1/9th of the actual peak RAM usage.
Claude пре 6 месеци
родитељ
комит
b1c6a55b62
1 измењених фајлова са 22 додато и 3 уклоњено
  1. 22 3
      core/pkg/opencost/allocation.go

+ 22 - 3
core/pkg/opencost/allocation.go

@@ -1428,9 +1428,28 @@ func (a *Allocation) add(that *Allocation) {
 	// Sum LoadBalancer Allocations
 	// Sum LoadBalancer Allocations
 	a.LoadBalancers = a.LoadBalancers.Add(that.LoadBalancers)
 	a.LoadBalancers = a.LoadBalancers.Add(that.LoadBalancers)
 
 
-	// Any data that is in a "raw allocation only" is not valid in any
-	// sort of cumulative Allocation (like one that is added).
-	a.RawAllocationOnly = nil
+	// Aggregate RawAllocationOnly data by taking the maximum of max values
+	// Max values represent peak usage at a point in time, so when combining
+	// allocations, we want the highest peak among all combined allocations.
+	if a.RawAllocationOnly != nil && that.RawAllocationOnly != nil {
+		// Both have RawAllocationOnly data, take max of each field
+		if that.RawAllocationOnly.CPUCoreUsageMax > a.RawAllocationOnly.CPUCoreUsageMax {
+			a.RawAllocationOnly.CPUCoreUsageMax = that.RawAllocationOnly.CPUCoreUsageMax
+		}
+		if that.RawAllocationOnly.RAMBytesUsageMax > a.RawAllocationOnly.RAMBytesUsageMax {
+			a.RawAllocationOnly.RAMBytesUsageMax = that.RawAllocationOnly.RAMBytesUsageMax
+		}
+		// Handle GPU max (pointer)
+		if that.RawAllocationOnly.GPUUsageMax != nil {
+			if a.RawAllocationOnly.GPUUsageMax == nil || *that.RawAllocationOnly.GPUUsageMax > *a.RawAllocationOnly.GPUUsageMax {
+				a.RawAllocationOnly.GPUUsageMax = that.RawAllocationOnly.GPUUsageMax
+			}
+		}
+	} else if that.RawAllocationOnly != nil {
+		// Only 'that' has RawAllocationOnly data, adopt it
+		a.RawAllocationOnly = that.RawAllocationOnly.Clone()
+	}
+	// If only 'a' has RawAllocationOnly data, keep it as-is
 }
 }
 
 
 func (thisLbAllocs LbAllocations) Add(thatLbAllocs LbAllocations) LbAllocations {
 func (thisLbAllocs LbAllocations) Add(thatLbAllocs LbAllocations) LbAllocations {