Przeglądaj źródła

Refactor alloc helpers to intervals + cleanup loops

Kaelan Patel 4 lat temu
rodzic
commit
2562eb7318

+ 7 - 8
pkg/costmodel/allocation.go

@@ -15,7 +15,6 @@ import (
 	"github.com/kubecost/cost-model/pkg/log"
 	"github.com/kubecost/cost-model/pkg/prom"
 	"k8s.io/apimachinery/pkg/labels"
-	"k8s.io/klog"
 )
 
 const (
@@ -416,6 +415,7 @@ func (cm *CostModel) ComputeAllocation(start, end time.Time, resolution time.Dur
 				}
 			}
 
+			break
 		}
 
 	}
@@ -428,12 +428,11 @@ func (cm *CostModel) ComputeAllocation(start, end time.Time, resolution time.Dur
 
 		// Get single-point intervals from alloc-PVC relation windows.
 		intervals := getIntervalPointsFromWindows(podIntervalMap)
-		pvcCostCoefficientMap := make(map[podKey][][]float64)
 
 		// Determine coefficients for each PVC-pod relation.
-		getPVCCostCoefficients(intervals, podIntervalMap, pvcCostCoefficientMap)
+		sharedPVCCostCoefficientMap[pvcKey] = getPVCCostCoefficients(intervals, podIntervalMap)
 
-		sharedPVCCostCoefficientMap[pvcKey] = pvcCostCoefficientMap
+		//sharedPVCCostCoefficientMap[pvcKey] = pvcCostCoefficientMap
 
 	}
 
@@ -489,7 +488,7 @@ func (cm *CostModel) ComputeAllocation(start, end time.Time, resolution time.Dur
 					if coeffComponents, ok := sharedPVCCostCoefficientMap[pvcKey][podKey]; ok {
 						cost *= getCoefficient(coeffComponents)
 					} else {
-						klog.Warningf("CostModel.ComputeAllocation: allocation %s and PVC %s have relation but no coeff", alloc.Name, pvc.Name)
+						log.Warningf("CostModel.ComputeAllocation: allocation %s and PVC %s have relation but no coeff", alloc.Name, pvc.Name)
 					}
 
 					// Apply the size and cost of the PV to the allocation, each
@@ -747,7 +746,7 @@ func applyCPUCoresAllocated(podMap map[podKey]*Pod, resCPUCoresAllocated []*prom
 
 		cpuCores := res.Values[0].Value
 		if cpuCores > MAX_CPU_CAP {
-			klog.Infof("[WARNING] Very large cpu allocation, clamping to %f", res.Values[0].Value*(pod.Allocations[container].Minutes()/60.0))
+			log.Infof("[WARNING] Very large cpu allocation, clamping to %f", res.Values[0].Value*(pod.Allocations[container].Minutes()/60.0))
 			cpuCores = 0.0
 		}
 		hours := pod.Allocations[container].Minutes() / 60.0
@@ -793,7 +792,7 @@ func applyCPUCoresRequested(podMap map[podKey]*Pod, resCPUCoresRequested []*prom
 			pod.Allocations[container].CPUCoreHours = res.Values[0].Value * (pod.Allocations[container].Minutes() / 60.0)
 		}
 		if pod.Allocations[container].CPUCores() > MAX_CPU_CAP {
-			klog.Infof("[WARNING] Very large cpu allocation, clamping! to %f", res.Values[0].Value*(pod.Allocations[container].Minutes()/60.0))
+			log.Infof("[WARNING] Very large cpu allocation, clamping! to %f", res.Values[0].Value*(pod.Allocations[container].Minutes()/60.0))
 			pod.Allocations[container].CPUCoreHours = res.Values[0].Value * (pod.Allocations[container].Minutes() / 60.0)
 		}
 
@@ -833,7 +832,7 @@ func applyCPUCoresUsedAvg(podMap map[podKey]*Pod, resCPUCoresUsedAvg []*prom.Que
 
 		pod.Allocations[container].CPUCoreUsageAverage = res.Values[0].Value
 		if res.Values[0].Value > MAX_CPU_CAP {
-			klog.Infof("[WARNING] Very large cpu USAGE, dropping outlier")
+			log.Infof("[WARNING] Very large cpu USAGE, dropping outlier")
 			pod.Allocations[container].CPUCoreUsageAverage = 0.0
 		}
 	}

+ 18 - 12
pkg/costmodel/allocation_helpers.go → pkg/costmodel/intervals.go

@@ -16,6 +16,14 @@ type IntervalPoint struct {
 	Key       podKey
 }
 
+// CostCoefficient is a representitive struct holding two fields which describe an interval:
+// 1. Proportion: The division of cost based on how many pods were running between those points
+// 2. Time: The ratio of the time between those points to the total time that pod was running
+type CostCoefficient struct {
+	Proportion float64
+	Time       float64
+}
+
 // NewIntervalPoint creates and returns a new IntervalPoint instance with given parameters.
 func NewIntervalPoint(time time.Time, pointType string, key podKey) IntervalPoint {
 	return IntervalPoint{
@@ -63,34 +71,30 @@ func sortIntervalPoints(intervals []IntervalPoint) {
 // getPVCCostCoefficients gets a coefficient which represents the scale
 // factor that each PVC in a pvcIntervalMap and corresponding slice of
 // IntervalPoints intervals uses to calculate a cost for that PVC's PV.
-func getPVCCostCoefficients(intervals []IntervalPoint, pvcIntervalMap map[podKey]kubecost.Window, pvcCostCoefficientMap map[podKey][][]float64) {
+func getPVCCostCoefficients(intervals []IntervalPoint, pvcIntervalMap map[podKey]kubecost.Window) map[podKey][][]float64 {
+
+	pvcCostCoefficientMap := make(map[podKey][][]float64)
 
 	// pvcCostCoefficientMap is mutated in this function. The format is
 	// such that the individual coefficient components are preserved for
 	// testing purposes.
 
-	var activePods float64
+	activePods := 1.0
 
-	activeKeys := make(map[podKey]struct{})
+	activeKeys := map[podKey]struct{}{
+		intervals[0].Key: struct{}{},
+	}
 
 	// For each interval i.e. for any time a pod-PVC relation ends or starts...
 	for i := 1; i < len(intervals); i++ {
 
+		// intervals will always have at least two IntervalPoints (one start/end)
 		point := intervals[i]
 		prevPoint := intervals[i-1]
 
-		// intervals will always have at least two IntervalPoints (one start/end)
-		if i == 1 {
-			activePods += 1
-			activeKeys[prevPoint.Key] = struct{}{}
-		}
-
 		// If the current point happens at a later time than the previous point
 		if !point.Time.Equal(prevPoint.Time) {
 			for key := range activeKeys {
-				// Add a two-long slice of float64 representing:
-				// 1. The division of cost based on how many pods were running between those points
-				// 2. The ratio of the time between those points to the total time that pod was running
 				pvcCostCoefficientMap[key] = append(
 					pvcCostCoefficientMap[key],
 					[]float64{1.0 / activePods, point.Time.Sub(prevPoint.Time).Minutes() / pvcIntervalMap[key].Duration().Minutes()},
@@ -111,6 +115,8 @@ func getPVCCostCoefficients(intervals []IntervalPoint, pvcIntervalMap map[podKey
 		}
 
 	}
+
+	return pvcCostCoefficientMap
 }
 
 // getCoefficient takes the components of a PVC-pod PV cost coefficient

+ 1 - 2
pkg/costmodel/allocation_helpers_test.go → pkg/costmodel/intervals_test.go

@@ -325,8 +325,7 @@ func TestGetPVCCostCoefficients(t *testing.T) {
 
 	for _, testCase := range cases {
 		t.Run(testCase.name, func(t *testing.T) {
-			result := make(map[podKey][][]float64)
-			getPVCCostCoefficients(testCase.intervals, testCase.pvcIntervalMap, result)
+			result := getPVCCostCoefficients(testCase.intervals, testCase.pvcIntervalMap)
 
 			if !reflect.DeepEqual(result, testCase.expected) {
 				t.Errorf("getPVCCostCoefficients test failed: %s: Got %+v but expected %+v", testCase.name, result, testCase.expected)