Copyright 2017 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Original file: https://github.com/kubernetes/autoscaler/tree/cluster-autoscaler-1.12.0-beta.1/vertical-pod-autoscaler/pkg/recommender/logic/estimator.go
*/
package recommend
import (
"math"
"reflect"
"time"
"k8s.io/klog/v2"
"openfuyao.com/colocation-management/pkg/colocation-manager/aggregate"
)
var (
houresPerDay = 24
minutesPerHour = 60
adjustedBaseValue = 1.0
)
type ResourceEstimator interface {
GetResourceEstimation(s *aggregate.AggregateContainerState) aggregate.Resources
}
type constEstimator struct {
resources aggregate.Resources
}
type percentileEstimator struct {
cpuPercentile float64
memoryPercentile float64
}
type marginEstimator struct {
marginFraction float64
baseEstimator ResourceEstimator
}
type minResourcesEstimator struct {
minResources aggregate.Resources
baseEstimator ResourceEstimator
}
type confidenceMultiplier struct {
multiplier float64
exponent float64
baseEstimator ResourceEstimator
}
func NewConstEstimator(resources aggregate.Resources) ResourceEstimator {
return &constEstimator{resources: resources}
}
func NewPercentileEstimator(cpuPercentile float64, memoryPercentile float64) ResourceEstimator {
return &percentileEstimator{cpuPercentile: cpuPercentile, memoryPercentile: memoryPercentile}
}
func WithMargin(marginFraction float64, baseEstimator ResourceEstimator) ResourceEstimator {
return &marginEstimator{marginFraction: marginFraction, baseEstimator: baseEstimator}
}
func WithMinResources(minResources aggregate.Resources, baseEstimator ResourceEstimator) ResourceEstimator {
return &minResourcesEstimator{minResources: minResources, baseEstimator: baseEstimator}
}
func WithConfidenceMultiplier(multiplier, exponent float64, baseEstimator ResourceEstimator) ResourceEstimator {
return &confidenceMultiplier{multiplier: multiplier, exponent: exponent, baseEstimator: baseEstimator}
}
func (e *constEstimator) GetResourceEstimation(s *aggregate.AggregateContainerState) aggregate.Resources {
return e.resources
}
func (e *percentileEstimator) GetResourceEstimation(s *aggregate.AggregateContainerState) aggregate.Resources {
if reflect.DeepEqual(s, &aggregate.AggregateContainerState{}) {
klog.Errorf("AggregateContainerState is nil")
return aggregate.Resources{
aggregate.ResourceCPU: aggregate.CPUAmountFromCores(0.0),
aggregate.ResourceMemory: aggregate.MemoryAmountFromBytes(0.0),
}
}
return aggregate.Resources{
aggregate.ResourceCPU: aggregate.CPUAmountFromCores(
s.AggregateCPUUsage.Percentile(e.cpuPercentile)),
aggregate.ResourceMemory: aggregate.MemoryAmountFromBytes(
s.AggregateMemoryPeaks.Percentile(e.memoryPercentile)),
}
}
func getConfidence(s *aggregate.AggregateContainerState) float64 {
lifespanInDays := float64(s.LastSampleStart.Sub(s.FirstSampleStart)) / float64(time.Hour*time.Duration(houresPerDay))
samplesAmount := float64(s.TotalSamplesCount) / (float64(minutesPerHour * houresPerDay))
return math.Min(lifespanInDays, samplesAmount)
}
func (e *confidenceMultiplier) GetResourceEstimation(s *aggregate.AggregateContainerState) aggregate.Resources {
confidence := getConfidence(s)
originalResources := e.baseEstimator.GetResourceEstimation(s)
scaledResources := make(aggregate.Resources)
for resource, resourceAmount := range originalResources {
scaledResources[resource] = aggregate.ScaleResource(
resourceAmount, math.Pow(adjustedBaseValue+e.multiplier/confidence, e.exponent))
}
return scaledResources
}
func (e *marginEstimator) GetResourceEstimation(s *aggregate.AggregateContainerState) aggregate.Resources {
originalResources := e.baseEstimator.GetResourceEstimation(s)
newResources := make(aggregate.Resources)
for resource, resourceAmount := range originalResources {
margin := aggregate.ScaleResource(resourceAmount, e.marginFraction)
newResources[resource] = originalResources[resource] + margin
}
return newResources
}
func (e *minResourcesEstimator) GetResourceEstimation(s *aggregate.AggregateContainerState) aggregate.Resources {
originalResources := e.baseEstimator.GetResourceEstimation(s)
newResources := make(aggregate.Resources)
for resource, resourceAmount := range originalResources {
if resourceAmount < e.minResources[resource] {
resourceAmount = e.minResources[resource]
}
newResources[resource] = resourceAmount
}
return newResources
}