Просмотр исходного кода

begin working on tests

Signed-off-by: Alex Meijer <ameijer@kubecost.com>
Alex Meijer 3 лет назад
Родитель
Сommit
b562be12b4
2 измененных файлов с 215 добавлено и 685 удалено
  1. 154 180
      pkg/kubecost/allocation.go
  2. 61 505
      pkg/kubecost/allocation_test.go

+ 154 - 180
pkg/kubecost/allocation.go

@@ -246,49 +246,24 @@ func (pva *PVAllocation) Equal(that *PVAllocation) bool {
 		util.IsApproximately(pva.Cost, that.Cost)
 }
 
-// used to compute the average of 2 PARCs. A PARC is a dimensonless
-// percentage that loses information needed when finding an average
-// to that end, we track the percentage and resource usage of the
-// component used to make the parc, to allow us to average two PARCs
-type ParcsComponent struct {
-	TotalCost       float64
-	UsageProportion float64
-}
-
-func (p *ParcsComponent) Clone() ParcsComponent {
-	return ParcsComponent{
-		TotalCost:       p.TotalCost,
-		UsageProportion: p.UsageProportion,
-	}
-}
-
 type ProportionalAssetResourceCost struct {
-	Cluster                    string           `json:"cluster"`
-	Node                       string           `json:"node,omitempty"`
-	ProviderID                 string           `json:"providerID,omitempty"`
-	CPUPercentage              float64          `json:"cpuPercentage"`
-	GPUPercentage              float64          `json:"gpuPercentage"`
-	RAMPercentage              float64          `json:"ramPercentage"`
-	NodeResourceCostPercentage float64          `json:"nodeResourceCostPercentage"`
-	GPUComponents              []ParcsComponent `json:"-"`
-	CPUComponents              []ParcsComponent `json:"-"`
-	RAMComponents              []ParcsComponent `json:"-"`
+	Cluster                    string  `json:"cluster"`
+	Node                       string  `json:"node,omitempty"`
+	ProviderID                 string  `json:"providerID,omitempty"`
+	CPUPercentage              float64 `json:"cpuPercentage"`
+	GPUPercentage              float64 `json:"gpuPercentage"`
+	RAMPercentage              float64 `json:"ramPercentage"`
+	NodeResourceCostPercentage float64 `json:"nodeResourceCostPercentage"`
+	GPUTotalCost               float64 `json:"-"`
+	GPUProportionalCost        float64 `json:"-"`
+	CPUTotalCost               float64 `json:"-"`
+	CPUProportionalCost        float64 `json:"-"`
+	RAMTotalCost               float64 `json:"-"`
+	RAMProportionalCost        float64 `json:"-"`
 }
 
 func (parc ProportionalAssetResourceCost) Clone() ProportionalAssetResourceCost {
-	gpuComps := []ParcsComponent{}
-	cpuComps := []ParcsComponent{}
-	ramComps := []ParcsComponent{}
 
-	for _, gpuComp := range parc.GPUComponents {
-		gpuComps = append(gpuComps, gpuComp.Clone())
-	}
-	for _, cpuComp := range parc.CPUComponents {
-		cpuComps = append(cpuComps, cpuComp.Clone())
-	}
-	for _, ramComp := range parc.RAMComponents {
-		ramComps = append(ramComps, ramComp.Clone())
-	}
 	return ProportionalAssetResourceCost{
 		Cluster:                    parc.Cluster,
 		Node:                       parc.Node,
@@ -297,9 +272,12 @@ func (parc ProportionalAssetResourceCost) Clone() ProportionalAssetResourceCost
 		GPUPercentage:              parc.GPUPercentage,
 		RAMPercentage:              parc.RAMPercentage,
 		NodeResourceCostPercentage: parc.NodeResourceCostPercentage,
-		RAMComponents:              ramComps,
-		CPUComponents:              cpuComps,
-		GPUComponents:              gpuComps,
+		RAMTotalCost:               parc.RAMTotalCost,
+		CPUTotalCost:               parc.CPUTotalCost,
+		GPUTotalCost:               parc.GPUTotalCost,
+		RAMProportionalCost:        parc.RAMProportionalCost,
+		CPUProportionalCost:        parc.CPUTotalCost,
+		GPUProportionalCost:        parc.GPUProportionalCost,
 	}
 }
 func (parc ProportionalAssetResourceCost) Key(insertByNode bool) string {
@@ -322,91 +300,66 @@ func (parcs ProportionalAssetResourceCosts) Clone() ProportionalAssetResourceCos
 	return cloned
 }
 
-func (parcs ProportionalAssetResourceCosts) Insert(parc ProportionalAssetResourceCost, insertByNode, isAccumulation bool) {
+func (parcs ProportionalAssetResourceCosts) Insert(parc ProportionalAssetResourceCost, insertByNode bool) {
 	if !insertByNode {
 		parc.Node = ""
 		parc.ProviderID = ""
 	}
 	if curr, ok := parcs[parc.Key(insertByNode)]; ok {
 
-		CPUPercentage := curr.CPUPercentage + parc.CPUPercentage
-		GPUPercentage := curr.GPUPercentage + parc.GPUPercentage
-		RAMPercentage := curr.RAMPercentage + parc.RAMPercentage
-
 		toInsert := ProportionalAssetResourceCost{
-			Node:                       curr.Node,
-			Cluster:                    curr.Cluster,
-			ProviderID:                 curr.ProviderID,
-			CPUPercentage:              CPUPercentage,
-			GPUPercentage:              GPUPercentage,
-			RAMPercentage:              RAMPercentage,
-			NodeResourceCostPercentage: curr.NodeResourceCostPercentage + parc.NodeResourceCostPercentage,
-			CPUComponents:              append(curr.CPUComponents, parc.CPUComponents...),
-			GPUComponents:              append(curr.GPUComponents, parc.GPUComponents...),
-			RAMComponents:              append(curr.RAMComponents, parc.RAMComponents...),
-		}
-
-		if isAccumulation {
-			// when accumulating, use the usage hours to perform a weighted average
-			toInsert.CPUPercentage = weightedParcComponentsAverage(toInsert.CPUComponents)
-			toInsert.GPUPercentage = weightedParcComponentsAverage(toInsert.GPUComponents)
-			toInsert.RAMPercentage = weightedParcComponentsAverage(toInsert.RAMComponents)
-			toInsert.NodeResourceCostPercentage = weightedNodeTotalCostAverage(toInsert.CPUComponents, toInsert.GPUComponents, toInsert.RAMComponents)
-		}
-
+			Node:                curr.Node,
+			Cluster:             curr.Cluster,
+			ProviderID:          curr.ProviderID,
+			CPUTotalCost:        curr.CPUTotalCost + parc.CPUTotalCost,
+			CPUProportionalCost: curr.CPUProportionalCost + parc.CPUProportionalCost,
+			RAMTotalCost:        curr.RAMTotalCost + parc.RAMTotalCost,
+			RAMProportionalCost: curr.RAMProportionalCost + parc.RAMProportionalCost,
+			GPUProportionalCost: curr.GPUProportionalCost + parc.GPUProportionalCost,
+			GPUTotalCost:        curr.GPUTotalCost + parc.GPUTotalCost,
+		}
+
+		computePercentages(&toInsert)
 		parcs[parc.Key(insertByNode)] = toInsert
 	} else {
+		computePercentages(&parc)
 		parcs[parc.Key(insertByNode)] = parc
 	}
 }
 
-func weightedNodeTotalCostAverage(cpuComponents, gpuComponents, ramComponents []ParcsComponent) float64 {
+func computePercentages(toInsert *ProportionalAssetResourceCost) {
+	// compute percentages
+	totalCost := toInsert.RAMTotalCost + toInsert.CPUTotalCost + toInsert.GPUTotalCost
 
-	totalRamCost := 0.0
-	for _, ramComponent := range ramComponents {
-		totalRamCost += ramComponent.TotalCost
+	if toInsert.CPUTotalCost > 0 {
+		toInsert.CPUPercentage = toInsert.CPUProportionalCost / toInsert.CPUTotalCost
 	}
 
-	totalCPUCost := 0.0
-	for _, cpuComponent := range cpuComponents {
-		totalCPUCost += cpuComponent.TotalCost
+	if toInsert.GPUTotalCost > 0 {
+		toInsert.GPUPercentage = toInsert.GPUProportionalCost / toInsert.GPUTotalCost
 	}
 
-	totalGPUCost := 0.0
-	for _, gpuComponent := range gpuComponents {
-		totalGPUCost += gpuComponent.TotalCost
+	if toInsert.RAMTotalCost > 0 {
+		toInsert.RAMPercentage = toInsert.RAMProportionalCost / toInsert.RAMTotalCost
 	}
 
-	totalCost := totalCPUCost + totalGPUCost + totalRamCost
-
-	var ramFraction, cpuFraction, gpuFraction float64
-
-	// only compute fraction if totalCost is nonzero, otherwise returns in NaN
-	if totalCost > 0 {
-		ramFraction = totalRamCost / totalCost
-		cpuFraction = totalCPUCost / totalCost
-		gpuFraction = totalGPUCost / totalCost
+	ramFraction := toInsert.RAMTotalCost / totalCost
+	if ramFraction != ramFraction || ramFraction < 0 {
+		ramFraction = 0
 	}
 
-	// compute the resource usage percentage based on the weighted fractions
-	nodeResourceCostPercentage := (weightedParcComponentsAverage(ramComponents) * ramFraction) + (weightedParcComponentsAverage(cpuComponents) * cpuFraction) + (weightedParcComponentsAverage(gpuComponents) * gpuFraction)
-
-	return nodeResourceCostPercentage
-}
-func weightedParcComponentsAverage(components []ParcsComponent) float64 {
-	totalResourceCosts := 0.0
-	costOfResource := 0.0
-	for _, component := range components {
-		totalResourceCosts += component.TotalCost
-
-		costOfResource += component.TotalCost * component.UsageProportion
-
+	cpuFraction := toInsert.CPUTotalCost / totalCost
+	if cpuFraction != cpuFraction || cpuFraction < 0 {
+		cpuFraction = 0
 	}
 
-	if totalResourceCosts <= 0 {
-		return 0
+	gpuFraction := toInsert.GPUTotalCost / totalCost
+	if gpuFraction != gpuFraction || gpuFraction < 0 {
+		gpuFraction = 0
 	}
-	return costOfResource / totalResourceCosts
+
+	toInsert.NodeResourceCostPercentage = (toInsert.RAMPercentage * ramFraction) +
+		(toInsert.CPUPercentage * cpuFraction) + (toInsert.GPUPercentage * gpuFraction)
 }
 
 func (parcs ProportionalAssetResourceCosts) Add(that ProportionalAssetResourceCosts, isAccumulation bool) {
@@ -417,7 +370,7 @@ func (parcs ProportionalAssetResourceCosts) Add(that ProportionalAssetResourceCo
 		if parc.Node == "" {
 			insertByNode = false
 		}
-		parcs.Insert(parc, insertByNode, isAccumulation)
+		parcs.Insert(parc, insertByNode)
 	}
 }
 
@@ -1278,35 +1231,13 @@ func (as *AllocationSet) AggregateBy(aggregateBy []string, options *AllocationAg
 		}
 	}
 
-	// (2b) If proportional asset resource costs are to be included, derive them
-	// from idle coefficients and add them to the allocations.
+	// (2b) If proportional asset resource costs are to be included, compute them
+	// and add them to the allocations.
 	if options.IncludeProportionalAssetResourceCosts {
-		var parcCoefficients map[string]map[string]map[string]float64
-		if parcSet.Length() > 0 {
-			parcCoefficients, allocatedTotalsMap, err = computeIdleCoeffs(options, as, shareSet)
-			if err != nil {
-				log.Warnf("AllocationSet.AggregateBy: compute parc idle coeff: %s", err)
-				return fmt.Errorf("error computing parc coefficients: %s", err)
-			}
-		}
-		if parcCoefficients == nil {
-			return fmt.Errorf("cannot include proportional resource costs because parc coefficients are nil")
-		}
-
-		for _, alloc := range as.Allocations {
-			// Create an empty set of proportional asset resource costs,
-			// regardless of whether or not we're successful in deriving them.
-			alloc.ProportionalAssetResourceCosts = ProportionalAssetResourceCosts{}
-
-			// Attempt to derive proportional asset resource costs from idle
-			// coefficients, and insert them into the set if successful.
-			parc, err := deriveProportionalAssetResourceCostsFromIdleCoefficients(parcCoefficients, allocatedTotalsMap, alloc, options)
-			if err != nil {
-				log.Debugf("AggregateBy: failed to derive proportional asset resource costs from idle coefficients for %s: %s", alloc.Name, err)
-				continue
-			}
-
-			alloc.ProportionalAssetResourceCosts.Insert(parc, options.IdleByNode, false)
+		err := deriveProportionalAssetResourceCosts(options, as, shareSet)
+		if err != nil {
+			log.Debugf("AggregateBy: failed to derive proportional asset resource costs from idle coefficients: %s", err)
+			return fmt.Errorf("AggregateBy: failed to derive proportional asset resource costs from idle coefficients: %s", err)
 		}
 	}
 
@@ -1876,68 +1807,111 @@ func computeIdleCoeffs(options *AllocationAggregationOptions, as *AllocationSet,
 	return coeffs, totals, nil
 }
 
-func deriveProportionalAssetResourceCostsFromIdleCoefficients(idleCoeffs map[string]map[string]map[string]float64, totals map[string]map[string]float64, allocation *Allocation, options *AllocationAggregationOptions) (ProportionalAssetResourceCost, error) {
-	idleId, err := allocation.getIdleId(options)
-	if err != nil {
-		return ProportionalAssetResourceCost{}, fmt.Errorf("failed to get idle ID for allocation %s", allocation.Name)
-	}
+func deriveProportionalAssetResourceCosts(options *AllocationAggregationOptions, as *AllocationSet, shareSet *AllocationSet) error {
 
-	if _, ok := idleCoeffs[idleId]; !ok {
-		return ProportionalAssetResourceCost{}, fmt.Errorf("failed to find idle coeffs for idle ID %s", idleId)
-	}
+	// Compute idle coefficients, then save them in AllocationAggregationOptions
+	// [idle_id][allocation name][resource] = [coeff]
+	coeffs := map[string]map[string]map[string]float64{}
+
+	// Compute totals per resource for CPU, GPU, RAM, and PV
+	// [idle_id][resource] = [total]
+	totals := map[string]map[string]float64{}
+
+	// Record allocation values first, then normalize by totals to get percentages
+	for _, alloc := range as.Allocations {
+		if alloc.IsIdle() {
+			// Skip idle allocations in coefficient calculation
+			continue
+		}
+
+		idleId, err := alloc.getIdleId(options)
+		if err != nil {
+			log.DedupedWarningf(3, "Missing Idle Key for %s", alloc.Name)
+		}
+
+		// get the name key for the allocation
+		name := alloc.Name
+
+		// Create key based tables if they don't exist
+		if _, ok := coeffs[idleId]; !ok {
+			coeffs[idleId] = map[string]map[string]float64{}
+		}
+		if _, ok := totals[idleId]; !ok {
+			totals[idleId] = map[string]float64{}
+		}
+
+		if _, ok := coeffs[idleId][name]; !ok {
+			coeffs[idleId][name] = map[string]float64{}
+		}
+
+		coeffs[idleId][name]["cpu"] += alloc.CPUTotalCost()
+		coeffs[idleId][name]["gpu"] += alloc.GPUTotalCost()
+		coeffs[idleId][name]["ram"] += alloc.RAMTotalCost()
 
-	if _, ok := idleCoeffs[idleId][allocation.Name]; !ok {
-		return ProportionalAssetResourceCost{}, fmt.Errorf("failed to find idle coeffs for allocation %s", allocation.Name)
+		totals[idleId]["cpu"] += alloc.CPUTotalCost()
+		totals[idleId]["gpu"] += alloc.GPUTotalCost()
+		totals[idleId]["ram"] += alloc.RAMTotalCost()
 	}
 
-	cpuPct := idleCoeffs[idleId][allocation.Name]["cpu"]
-	gpuPct := idleCoeffs[idleId][allocation.Name]["gpu"]
-	ramPct := idleCoeffs[idleId][allocation.Name]["ram"]
+	// Do the same for shared allocations
+	for _, alloc := range shareSet.Allocations {
+		if alloc.IsIdle() {
+			// Skip idle allocations in coefficient calculation
+			continue
+		}
+
+		// idleId will be providerId or cluster
+		idleId, err := alloc.getIdleId(options)
+		if err != nil {
+			log.DedupedWarningf(3, "Missing Idle Key in share set for %s", alloc.Name)
+		}
+
+		// get the name key for the allocation
+		name := alloc.Name
+
+		// Create idleId based tables if they don't exist
+		if _, ok := coeffs[idleId]; !ok {
+			coeffs[idleId] = map[string]map[string]float64{}
+		}
+		if _, ok := totals[idleId]; !ok {
+			totals[idleId] = map[string]float64{}
+		}
 
-	// compute how much each component (cpu, gpu, ram) contributes to the overall price
-	totalCost := totals[idleId]["ram"] + totals[idleId]["gpu"] + totals[idleId]["cpu"]
+		if _, ok := coeffs[idleId][name]; !ok {
+			coeffs[idleId][name] = map[string]float64{}
+		}
 
-	var ramFraction, cpuFraction, gpuFraction float64
+		coeffs[idleId][name]["cpu"] += alloc.CPUTotalCost()
+		coeffs[idleId][name]["gpu"] += alloc.GPUTotalCost()
+		coeffs[idleId][name]["ram"] += alloc.RAMTotalCost()
 
-	// only compute fraction if totalCost is nonzero, otherwise returns in NaN
-	if totalCost > 0 {
-		ramFraction = totals[idleId]["ram"] / totalCost
-		cpuFraction = totals[idleId]["cpu"] / totalCost
-		gpuFraction = totals[idleId]["gpu"] / totalCost
+		totals[idleId]["cpu"] += alloc.CPUTotalCost()
+		totals[idleId]["gpu"] += alloc.GPUTotalCost()
+		totals[idleId]["ram"] += alloc.RAMTotalCost()
 	}
 
-	// compute the resource usage percentage based on the weighted fractions
-	nodeResourceCostPercentage := (ramPct * ramFraction) + (cpuPct * cpuFraction) + (gpuPct * gpuFraction)
+	// after totals are computed, loop through and set parcs on allocations
+	for _, alloc := range as.Allocations {
+		idleId, err := alloc.getIdleId(options)
+		if err != nil {
+			log.DedupedWarningf(3, "Missing Idle Key in share set for %s", alloc.Name)
+		}
 
-	parc := ProportionalAssetResourceCost{
-		Cluster:                    allocation.Properties.Cluster,
-		Node:                       allocation.Properties.Node,
-		ProviderID:                 allocation.Properties.ProviderID,
-		CPUPercentage:              cpuPct,
-		GPUPercentage:              gpuPct,
-		RAMPercentage:              ramPct,
-		NodeResourceCostPercentage: nodeResourceCostPercentage,
-		CPUComponents: []ParcsComponent{
-			{
-				TotalCost:       totals[idleId]["cpu"],
-				UsageProportion: idleCoeffs[idleId][allocation.Name]["cpu"],
-			},
-		},
-		GPUComponents: []ParcsComponent{
-			{
-				TotalCost:       totals[idleId]["gpu"],
-				UsageProportion: idleCoeffs[idleId][allocation.Name]["gpu"],
-			},
-		},
-		RAMComponents: []ParcsComponent{
-			{
-				TotalCost:       totals[idleId]["ram"],
-				UsageProportion: idleCoeffs[idleId][allocation.Name]["ram"],
-			},
-		},
+		alloc.ProportionalAssetResourceCosts = ProportionalAssetResourceCosts{}
+		alloc.ProportionalAssetResourceCosts.Insert(ProportionalAssetResourceCost{
+			Cluster:             alloc.Properties.Cluster,
+			Node:                alloc.Properties.Node,
+			ProviderID:          alloc.Properties.ProviderID,
+			GPUTotalCost:        totals[idleId]["gpu"],
+			CPUTotalCost:        totals[idleId]["cpu"],
+			RAMTotalCost:        totals[idleId]["ram"],
+			GPUProportionalCost: coeffs[idleId][alloc.Name]["gpu"],
+			CPUProportionalCost: coeffs[idleId][alloc.Name]["cpu"],
+			RAMProportionalCost: coeffs[idleId][alloc.Name]["ram"],
+		}, options.IdleByNode)
 	}
 
-	return parc, nil
+	return nil
 }
 
 // getIdleId returns the providerId or cluster of an Allocation depending on the IdleByNode

+ 61 - 505
pkg/kubecost/allocation_test.go

@@ -517,9 +517,6 @@ func assertParcResults(t *testing.T, as *AllocationSet, msg string, exps map[str
 	for allocKey, a := range as.Allocations {
 		for key, actualParc := range a.ProportionalAssetResourceCosts {
 			expectedParcs := exps[allocKey]
-			sortParcsComponent(actualParc.RAMComponents)
-			sortParcsComponent(actualParc.CPUComponents)
-			sortParcsComponent(actualParc.GPUComponents)
 			if !reflect.DeepEqual(expectedParcs[key], actualParc) {
 				t.Fatalf("actual PARC %v did not match expected PARC %v", actualParc, expectedParcs[key])
 			}
@@ -528,19 +525,6 @@ func assertParcResults(t *testing.T, as *AllocationSet, msg string, exps map[str
 	}
 }
 
-func sortParcsComponent(parcs []ParcsComponent) {
-	var n = len(parcs)
-	for i := 1; i < n; i++ {
-		j := i
-		for j > 0 {
-			if parcs[j-1].UsageProportion > parcs[j].UsageProportion {
-				parcs[j-1], parcs[j] = parcs[j], parcs[j-1]
-			}
-			j = j - 1
-		}
-	}
-}
-
 func assertAllocationTotals(t *testing.T, as *AllocationSet, msg string, exps map[string]float64) {
 	for _, a := range as.Allocations {
 		if exp, ok := exps[a.Name]; ok {
@@ -1095,52 +1079,16 @@ func TestAllocationSet_AggregateBy(t *testing.T) {
 						Cluster:                    "cluster1",
 						Node:                       "",
 						ProviderID:                 "",
-						CPUPercentage:              0.5,
-						GPUPercentage:              0.5,
-						RAMPercentage:              0.8125,
-						NodeResourceCostPercentage: 0.6785714285714285,
-						GPUComponents: []ParcsComponent{
-							{
-								TotalCost:       6,
-								UsageProportion: 0.16666666666666666,
-							},
-							{
-								TotalCost:       6,
-								UsageProportion: 0.16666666666666666,
-							},
-							{
-								TotalCost:       6,
-								UsageProportion: 0.16666666666666666,
-							},
-						},
-						CPUComponents: []ParcsComponent{
-							{
-								TotalCost:       6,
-								UsageProportion: 0.16666666666666666,
-							},
-							{
-								TotalCost:       6,
-								UsageProportion: 0.16666666666666666,
-							},
-							{
-								TotalCost:       6,
-								UsageProportion: 0.16666666666666666,
-							},
-						},
-						RAMComponents: []ParcsComponent{
-							{
-								TotalCost:       16,
-								UsageProportion: 0.0625,
-							},
-							{
-								TotalCost:       16,
-								UsageProportion: 0.0625,
-							},
-							{
-								TotalCost:       16,
-								UsageProportion: 0.6875,
-							},
-						},
+						CPUPercentage:              0.16666666666666666,
+						GPUPercentage:              0.16666666666666666,
+						RAMPercentage:              0.2708333333333333,
+						NodeResourceCostPercentage: 0.22619047619047614,
+						GPUTotalCost:               18,
+						GPUProportionalCost:        3,
+						CPUTotalCost:               18,
+						CPUProportionalCost:        3,
+						RAMTotalCost:               48,
+						RAMProportionalCost:        13,
 					},
 				},
 				"namespace2": {
@@ -1148,103 +1096,31 @@ func TestAllocationSet_AggregateBy(t *testing.T) {
 						Cluster:                    "cluster1",
 						Node:                       "",
 						ProviderID:                 "",
-						CPUPercentage:              0.5,
-						GPUPercentage:              0.5,
-						RAMPercentage:              0.1875,
-						NodeResourceCostPercentage: 0.3214285714285714,
-						GPUComponents: []ParcsComponent{
-							{
-								TotalCost:       6,
-								UsageProportion: 0.16666666666666666,
-							},
-							{
-								TotalCost:       6,
-								UsageProportion: 0.16666666666666666,
-							},
-							{
-								TotalCost:       6,
-								UsageProportion: 0.16666666666666666,
-							},
-						},
-						CPUComponents: []ParcsComponent{
-							{
-								TotalCost:       6,
-								UsageProportion: 0.16666666666666666,
-							},
-							{
-								TotalCost:       6,
-								UsageProportion: 0.16666666666666666,
-							},
-							{
-								TotalCost:       6,
-								UsageProportion: 0.16666666666666666,
-							},
-						},
-						RAMComponents: []ParcsComponent{
-							{
-								TotalCost:       16,
-								UsageProportion: 0.0625,
-							},
-							{
-								TotalCost:       16,
-								UsageProportion: 0.0625,
-							},
-							{
-								TotalCost:       16,
-								UsageProportion: 0.0625,
-							},
-						},
+						CPUPercentage:              0.16666666666666666,
+						GPUPercentage:              0.16666666666666666,
+						RAMPercentage:              0.0625,
+						NodeResourceCostPercentage: 0.10714285714285714,
+						GPUTotalCost:               18,
+						GPUProportionalCost:        3,
+						CPUTotalCost:               18,
+						CPUProportionalCost:        3,
+						RAMTotalCost:               48,
+						RAMProportionalCost:        3,
 					},
 					"cluster2": ProportionalAssetResourceCost{
 						Cluster:                    "cluster2",
 						Node:                       "",
 						ProviderID:                 "",
-						CPUPercentage:              0.5,
-						GPUPercentage:              0.5,
-						RAMPercentage:              0.5,
-						NodeResourceCostPercentage: 0.5,
-						GPUComponents: []ParcsComponent{
-							{
-								TotalCost:       6,
-								UsageProportion: 0.16666666666666666,
-							},
-							{
-								TotalCost:       6,
-								UsageProportion: 0.16666666666666666,
-							},
-							{
-								TotalCost:       6,
-								UsageProportion: 0.16666666666666666,
-							},
-						},
-						CPUComponents: []ParcsComponent{
-							{
-								TotalCost:       6,
-								UsageProportion: 0.16666666666666666,
-							},
-							{
-								TotalCost:       6,
-								UsageProportion: 0.16666666666666666,
-							},
-							{
-								TotalCost:       6,
-								UsageProportion: 0.16666666666666666,
-							},
-						},
-						RAMComponents: []ParcsComponent{
-							{
-								TotalCost:       6,
-								UsageProportion: 0.16666666666666666,
-							},
-							{
-								TotalCost:       6,
-								UsageProportion: 0.16666666666666666,
-							},
-							{
-								TotalCost:       6,
-								UsageProportion: 0.16666666666666666,
-							},
-						},
+						CPUPercentage:              0.16666666666666666,
+						GPUPercentage:              0.16666666666666666,
+						RAMPercentage:              0.16666666666666666,
+						NodeResourceCostPercentage: 0.16666666666666666,
+						GPUTotalCost:               18,
+						GPUProportionalCost:        3,
+						CPUTotalCost:               18,
+						CPUProportionalCost:        3,
+						RAMTotalCost:               18,
+						RAMProportionalCost:        3,
 					},
 				},
 			},
@@ -1663,48 +1539,6 @@ func TestAllocationSet_AggregateBy(t *testing.T) {
 						GPUPercentage:              0.5,
 						RAMPercentage:              0.8125,
 						NodeResourceCostPercentage: 0.6785714285714285,
-						GPUComponents: []ParcsComponent{
-							{
-								TotalCost:       6,
-								UsageProportion: 0.16666666666666666,
-							},
-							{
-								TotalCost:       6,
-								UsageProportion: 0.16666666666666666,
-							},
-							{
-								TotalCost:       6,
-								UsageProportion: 0.16666666666666666,
-							},
-						},
-						CPUComponents: []ParcsComponent{
-							{
-								TotalCost:       6,
-								UsageProportion: 0.16666666666666666,
-							},
-							{
-								TotalCost:       6,
-								UsageProportion: 0.16666666666666666,
-							},
-							{
-								TotalCost:       6,
-								UsageProportion: 0.16666666666666666,
-							},
-						},
-						RAMComponents: []ParcsComponent{
-							{
-								TotalCost:       16,
-								UsageProportion: 0.0625,
-							},
-							{
-								TotalCost:       16,
-								UsageProportion: 0.0625,
-							},
-							{
-								TotalCost:       16,
-								UsageProportion: 0.6875,
-							},
-						},
 					},
 					"cluster2,node2": ProportionalAssetResourceCost{
 						Cluster:                    "cluster2",
@@ -1725,48 +1559,6 @@ func TestAllocationSet_AggregateBy(t *testing.T) {
 						GPUPercentage:              0.5,
 						RAMPercentage:              0.1875,
 						NodeResourceCostPercentage: 0.3214285714285714,
-						GPUComponents: []ParcsComponent{
-							{
-								TotalCost:       6,
-								UsageProportion: 0.16666666666666666,
-							},
-							{
-								TotalCost:       6,
-								UsageProportion: 0.16666666666666666,
-							},
-							{
-								TotalCost:       6,
-								UsageProportion: 0.16666666666666666,
-							},
-						},
-						CPUComponents: []ParcsComponent{
-							{
-								TotalCost:       6,
-								UsageProportion: 0.16666666666666666,
-							},
-							{
-								TotalCost:       6,
-								UsageProportion: 0.16666666666666666,
-							},
-							{
-								TotalCost:       6,
-								UsageProportion: 0.16666666666666666,
-							},
-						},
-						RAMComponents: []ParcsComponent{
-							{
-								TotalCost:       16,
-								UsageProportion: 0.0625,
-							},
-							{
-								TotalCost:       16,
-								UsageProportion: 0.0625,
-							},
-							{
-								TotalCost:       16,
-								UsageProportion: 0.0625,
-							},
-						},
 					},
 					"cluster2,node1": ProportionalAssetResourceCost{
 						Cluster:                    "cluster2",
@@ -1776,36 +1568,6 @@ func TestAllocationSet_AggregateBy(t *testing.T) {
 						GPUPercentage:              1,
 						RAMPercentage:              1,
 						NodeResourceCostPercentage: 1,
-						GPUComponents: []ParcsComponent{
-							{
-								TotalCost:       2,
-								UsageProportion: 0.5,
-							},
-							{
-								TotalCost:       2,
-								UsageProportion: 0.5,
-							},
-						},
-						CPUComponents: []ParcsComponent{
-							{
-								TotalCost:       2,
-								UsageProportion: 0.5,
-							},
-							{
-								TotalCost:       2,
-								UsageProportion: 0.5,
-							},
-						},
-						RAMComponents: []ParcsComponent{
-							{
-								TotalCost:       2,
-								UsageProportion: 0.5,
-							},
-							{
-								TotalCost:       2,
-								UsageProportion: 0.5,
-							},
-						},
 					},
 					"cluster2,node2": ProportionalAssetResourceCost{
 						Cluster:                    "cluster2",
@@ -1815,24 +1577,6 @@ func TestAllocationSet_AggregateBy(t *testing.T) {
 						GPUPercentage:              0.5,
 						RAMPercentage:              0.5,
 						NodeResourceCostPercentage: 0.5,
-						GPUComponents: []ParcsComponent{
-							{
-								TotalCost:       2,
-								UsageProportion: 0.5,
-							},
-						},
-						CPUComponents: []ParcsComponent{
-							{
-								TotalCost:       2,
-								UsageProportion: 0.5,
-							},
-						},
-						RAMComponents: []ParcsComponent{
-							{
-								TotalCost:       2,
-								UsageProportion: 0.5,
-							},
-						},
 					},
 				},
 				"namespace3": {
@@ -1844,36 +1588,6 @@ func TestAllocationSet_AggregateBy(t *testing.T) {
 						GPUPercentage:              1,
 						RAMPercentage:              1,
 						NodeResourceCostPercentage: 1,
-						GPUComponents: []ParcsComponent{
-							{
-								TotalCost:       2,
-								UsageProportion: 0.5,
-							},
-							{
-								TotalCost:       2,
-								UsageProportion: 0.5,
-							},
-						},
-						CPUComponents: []ParcsComponent{
-							{
-								TotalCost:       2,
-								UsageProportion: 0.5,
-							},
-							{
-								TotalCost:       2,
-								UsageProportion: 0.5,
-							},
-						},
-						RAMComponents: []ParcsComponent{
-							{
-								TotalCost:       2,
-								UsageProportion: 0.5,
-							},
-							{
-								TotalCost:       2,
-								UsageProportion: 0.5,
-							},
-						},
 					},
 					"cluster2,node2": ProportionalAssetResourceCost{
 						Cluster:                    "cluster2",
@@ -1883,24 +1597,12 @@ func TestAllocationSet_AggregateBy(t *testing.T) {
 						GPUPercentage:              0.5,
 						RAMPercentage:              0.5,
 						NodeResourceCostPercentage: 0.5,
-						GPUComponents: []ParcsComponent{
-							{
-								TotalCost:       2,
-								UsageProportion: 0.5,
-							},
-						},
-						CPUComponents: []ParcsComponent{
-							{
-								TotalCost:       2,
-								UsageProportion: 0.5,
-							},
-						},
-						RAMComponents: []ParcsComponent{
-							{
-								TotalCost:       2,
-								UsageProportion: 0.5,
-							},
-						},
+						GPUTotalCost:               2,
+						GPUProportionalCost:        1,
+						CPUTotalCost:               2,
+						CPUProportionalCost:        1,
+						RAMTotalCost:               2,
+						RAMProportionalCost:        1,
 					},
 				},
 			},
@@ -2065,24 +1767,8 @@ func TestParcInsert(t *testing.T) {
 		GPUPercentage:              0,
 		RAMPercentage:              0,
 		NodeResourceCostPercentage: 0,
-		CPUComponents: []ParcsComponent{
-			{
-				TotalCost:       4,
-				UsageProportion: 0.125,
-			},
-		},
-		GPUComponents: []ParcsComponent{
-			{
-				TotalCost:       0,
-				UsageProportion: 0.0,
-			},
-		},
-		RAMComponents: []ParcsComponent{
-			{
-				TotalCost:       0,
-				UsageProportion: 0.0,
-			},
-		},
+		CPUTotalCost:               4,
+		CPUProportionalCost:        0.5,
 	}
 
 	pod1_hour2 := ProportionalAssetResourceCost{
@@ -2093,24 +1779,7 @@ func TestParcInsert(t *testing.T) {
 		GPUPercentage:              0,
 		RAMPercentage:              0,
 		NodeResourceCostPercentage: 0,
-		CPUComponents: []ParcsComponent{
-			{
-				TotalCost:       4,
-				UsageProportion: 0.0,
-			},
-		},
-		GPUComponents: []ParcsComponent{
-			{
-				TotalCost:       0,
-				UsageProportion: 0.0,
-			},
-		},
-		RAMComponents: []ParcsComponent{
-			{
-				TotalCost:       0,
-				UsageProportion: 0.0,
-			},
-		},
+		CPUTotalCost:               4,
 	}
 
 	pod1_hour3 := ProportionalAssetResourceCost{
@@ -2121,24 +1790,7 @@ func TestParcInsert(t *testing.T) {
 		GPUPercentage:              0,
 		RAMPercentage:              0,
 		NodeResourceCostPercentage: 0,
-		CPUComponents: []ParcsComponent{
-			{
-				TotalCost:       4,
-				UsageProportion: 0.0,
-			},
-		},
-		GPUComponents: []ParcsComponent{
-			{
-				TotalCost:       0,
-				UsageProportion: 0.0,
-			},
-		},
-		RAMComponents: []ParcsComponent{
-			{
-				TotalCost:       0,
-				UsageProportion: 0.0,
-			},
-		},
+		CPUTotalCost:               4,
 	}
 
 	pod2_hour1 := ProportionalAssetResourceCost{
@@ -2149,24 +1801,8 @@ func TestParcInsert(t *testing.T) {
 		GPUPercentage:              0,
 		RAMPercentage:              0,
 		NodeResourceCostPercentage: 0,
-		CPUComponents: []ParcsComponent{
-			{
-				TotalCost:       4,
-				UsageProportion: 0.5,
-			},
-		},
-		GPUComponents: []ParcsComponent{
-			{
-				TotalCost:       0,
-				UsageProportion: 0.0,
-			},
-		},
-		RAMComponents: []ParcsComponent{
-			{
-				TotalCost:       0,
-				UsageProportion: 0.0,
-			},
-		},
+		CPUTotalCost:               4,
+		CPUProportionalCost:        2,
 	}
 
 	pod2_hour2 := ProportionalAssetResourceCost{
@@ -2177,24 +1813,8 @@ func TestParcInsert(t *testing.T) {
 		GPUPercentage:              0,
 		RAMPercentage:              0,
 		NodeResourceCostPercentage: 0,
-		CPUComponents: []ParcsComponent{
-			{
-				TotalCost:       4,
-				UsageProportion: 0.25,
-			},
-		},
-		GPUComponents: []ParcsComponent{
-			{
-				TotalCost:       0,
-				UsageProportion: 0.0,
-			},
-		},
-		RAMComponents: []ParcsComponent{
-			{
-				TotalCost:       0,
-				UsageProportion: 0.0,
-			},
-		},
+		CPUTotalCost:               4,
+		CPUProportionalCost:        1,
 	}
 
 	pod2_hour3 := ProportionalAssetResourceCost{
@@ -2205,24 +1825,8 @@ func TestParcInsert(t *testing.T) {
 		GPUPercentage:              0,
 		RAMPercentage:              0,
 		NodeResourceCostPercentage: 0,
-		CPUComponents: []ParcsComponent{
-			{
-				TotalCost:       4,
-				UsageProportion: 0.375,
-			},
-		},
-		GPUComponents: []ParcsComponent{
-			{
-				TotalCost:       0,
-				UsageProportion: 0.0,
-			},
-		},
-		RAMComponents: []ParcsComponent{
-			{
-				TotalCost:       0,
-				UsageProportion: 0.0,
-			},
-		},
+		CPUTotalCost:               4,
+		CPUProportionalCost:        1.5,
 	}
 
 	pod3_hour1 := ProportionalAssetResourceCost{
@@ -2233,24 +1837,8 @@ func TestParcInsert(t *testing.T) {
 		GPUPercentage:              0,
 		RAMPercentage:              0,
 		NodeResourceCostPercentage: 0,
-		CPUComponents: []ParcsComponent{
-			{
-				TotalCost:       4,
-				UsageProportion: 0.25,
-			},
-		},
-		GPUComponents: []ParcsComponent{
-			{
-				TotalCost:       0,
-				UsageProportion: 0.0,
-			},
-		},
-		RAMComponents: []ParcsComponent{
-			{
-				TotalCost:       0,
-				UsageProportion: 0.0,
-			},
-		},
+		CPUTotalCost:               4,
+		CPUProportionalCost:        1,
 	}
 
 	pod3_hour2 := ProportionalAssetResourceCost{
@@ -2261,24 +1849,8 @@ func TestParcInsert(t *testing.T) {
 		GPUPercentage:              0,
 		RAMPercentage:              0,
 		NodeResourceCostPercentage: 0,
-		CPUComponents: []ParcsComponent{
-			{
-				TotalCost:       4,
-				UsageProportion: 0.25,
-			},
-		},
-		GPUComponents: []ParcsComponent{
-			{
-				TotalCost:       0,
-				UsageProportion: 0.0,
-			},
-		},
-		RAMComponents: []ParcsComponent{
-			{
-				TotalCost:       0,
-				UsageProportion: 0.0,
-			},
-		},
+		CPUTotalCost:               4,
+		CPUProportionalCost:        1,
 	}
 
 	pod3_hour3 := ProportionalAssetResourceCost{
@@ -2289,36 +1861,20 @@ func TestParcInsert(t *testing.T) {
 		GPUPercentage:              0,
 		RAMPercentage:              0,
 		NodeResourceCostPercentage: 0,
-		CPUComponents: []ParcsComponent{
-			{
-				TotalCost:       4,
-				UsageProportion: 0.25,
-			},
-		},
-		GPUComponents: []ParcsComponent{
-			{
-				TotalCost:       0,
-				UsageProportion: 0.0,
-			},
-		},
-		RAMComponents: []ParcsComponent{
-			{
-				TotalCost:       0,
-				UsageProportion: 0.0,
-			},
-		},
+		CPUTotalCost:               4,
+		CPUProportionalCost:        1,
 	}
 
 	parcs := ProportionalAssetResourceCosts{}
-	parcs.Insert(pod1_hour1, true, true)
-	parcs.Insert(pod1_hour2, true, true)
-	parcs.Insert(pod1_hour3, true, true)
-	parcs.Insert(pod2_hour1, true, true)
-	parcs.Insert(pod2_hour2, true, true)
-	parcs.Insert(pod2_hour3, true, true)
-	parcs.Insert(pod3_hour1, true, true)
-	parcs.Insert(pod3_hour2, true, true)
-	parcs.Insert(pod3_hour3, true, true)
+	parcs.Insert(pod1_hour1, true)
+	parcs.Insert(pod1_hour2, true)
+	parcs.Insert(pod1_hour3, true)
+	parcs.Insert(pod2_hour1, true)
+	parcs.Insert(pod2_hour2, true)
+	parcs.Insert(pod2_hour3, true)
+	parcs.Insert(pod3_hour1, true)
+	parcs.Insert(pod3_hour2, true)
+	parcs.Insert(pod3_hour3, true)
 	log.Debug("added all parcs")
 
 	expectedParcs := ProportionalAssetResourceCosts{