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-chart-1.0.2/vertical-pod-autoscaler/pkg/recommender/model/container.go
Copyright (c) 2024 China Unicom Digital Technology Co., Ltd.
Modifications:
Modified function addCPUSample addMemorySample
*/
package aggregate
import (
"time"
)
type ContainerUsageSample struct {
MeasureStart time.Time
Usage ResourceAmount
Request ResourceAmount
Resource ResourceName
}
type ContainerState struct {
Request Resources
LastCPUSampleStart time.Time
memoryPeak ResourceAmount
oomPeak ResourceAmount
WindowEnd time.Time
lastMemorySampleStart time.Time
aggregator ContainerStateAggregator
}
func NewContainerState(request Resources, aggregator ContainerStateAggregator) *ContainerState {
return &ContainerState{
Request: request,
LastCPUSampleStart: time.Time{},
WindowEnd: time.Time{},
lastMemorySampleStart: time.Time{},
aggregator: aggregator,
}
}
func (sample *ContainerUsageSample) isValid(expectedResource ResourceName) bool {
return sample.Usage >= 0 && sample.Resource == expectedResource
}
func (container *ContainerState) addCPUSample(sample *ContainerUsageSample) bool {
if !sample.isValid(ResourceCPU) || !sample.MeasureStart.After(container.LastCPUSampleStart) {
return false
}
container.aggregator.AddSample(sample)
container.LastCPUSampleStart = sample.MeasureStart
return true
}
func (container *ContainerState) GetMaxMemoryPeak() ResourceAmount {
return ResourceAmountMax(container.memoryPeak, container.oomPeak)
}
func (container *ContainerState) addMemorySample(sample *ContainerUsageSample, isOOM bool) bool {
ts := sample.MeasureStart
if !sample.isValid(ResourceMemory) ||
(!isOOM && ts.Before(container.lastMemorySampleStart)) {
return false
}
container.lastMemorySampleStart = ts
if container.WindowEnd.IsZero() {
container.WindowEnd = ts
}
addNewPeak := false
if ts.Before(container.WindowEnd) {
oldMaxMem := container.GetMaxMemoryPeak()
if oldMaxMem != 0 && sample.Usage > oldMaxMem {
oldPeak := ContainerUsageSample{
MeasureStart: container.WindowEnd,
Usage: oldMaxMem,
Request: sample.Request,
Resource: ResourceMemory,
}
container.aggregator.SubtractSample(&oldPeak)
addNewPeak = true
}
} else {
memoryAggregationInterval := GetAggregationsConfig().MemoryAggregationInterval
shift := ts.Sub(container.WindowEnd).Truncate(memoryAggregationInterval) + memoryAggregationInterval
container.WindowEnd = container.WindowEnd.Add(shift)
container.memoryPeak = 0
container.oomPeak = 0
addNewPeak = true
}
if addNewPeak {
newPeak := ContainerUsageSample{
MeasureStart: container.WindowEnd,
Usage: sample.Usage,
Request: sample.Request,
Resource: ResourceMemory,
}
container.aggregator.AddSample(&newPeak)
if isOOM {
container.oomPeak = sample.Usage
} else {
container.memoryPeak = sample.Usage
}
}
return true
}
func (container *ContainerState) AddSample(sample *ContainerUsageSample) bool {
switch sample.Resource {
case ResourceCPU:
return container.addCPUSample(sample)
case ResourceMemory:
return container.addMemorySample(sample, false)
default:
return false
}
}