This is copied verbatim for our older prototype. We'll use it as a starting point for building stats summary.
136 lines
3.8 KiB
Go
136 lines
3.8 KiB
Go
// Copyright 2015 Google Inc. All Rights Reserved.
|
|
//
|
|
// 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.
|
|
|
|
package utils
|
|
|
|
import (
|
|
"math"
|
|
"sort"
|
|
"time"
|
|
|
|
"github.com/golang/glog"
|
|
"github.com/google/cadvisor/info"
|
|
)
|
|
|
|
const milliSecondsToNanoSeconds = 1000000
|
|
const secondsToMilliSeconds = 1000
|
|
|
|
type uint64Slice []uint64
|
|
|
|
func (a uint64Slice) Len() int { return len(a) }
|
|
func (a uint64Slice) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
|
func (a uint64Slice) Less(i, j int) bool { return a[i] < a[j] }
|
|
|
|
// TODO(rjnagal): Move out when we update API.
|
|
type Percentiles struct {
|
|
// Average over the collected sample.
|
|
Mean uint64 `json:"mean"`
|
|
// Max seen over the collected sample.
|
|
Max uint64 `json:"max"`
|
|
// 90th percentile over the collected sample.
|
|
Ninety uint64 `json:"ninety"`
|
|
}
|
|
|
|
// Get 90th percentile of the provided samples. Round to integer.
|
|
func (self uint64Slice) Get90Percentile() uint64 {
|
|
count := self.Len()
|
|
if count == 0 {
|
|
return 0
|
|
}
|
|
sort.Sort(self)
|
|
n := float64(0.9 * (float64(count) + 1))
|
|
idx, frac := math.Modf(n)
|
|
index := int(idx)
|
|
percentile := float64(self[index-1])
|
|
if index > 1 || index < count {
|
|
percentile += frac * float64(self[index]-self[index-1])
|
|
}
|
|
return uint64(percentile)
|
|
}
|
|
|
|
type Mean struct {
|
|
// current count.
|
|
count uint64
|
|
// current mean.
|
|
Mean float64
|
|
}
|
|
|
|
func (self *Mean) Add(value uint64) {
|
|
self.count++
|
|
if self.count == 1 {
|
|
self.Mean = float64(value)
|
|
return
|
|
}
|
|
c := float64(self.count)
|
|
v := float64(value)
|
|
self.Mean = (self.Mean*(c-1) + v) / c
|
|
}
|
|
|
|
// Returns cpu and memory usage percentiles.
|
|
func GetPercentiles(stats []*info.ContainerStats) (Percentiles, Percentiles) {
|
|
lastCpu := uint64(0)
|
|
lastTime := time.Time{}
|
|
memorySamples := make(uint64Slice, 0, len(stats))
|
|
cpuSamples := make(uint64Slice, 0, len(stats)-1)
|
|
numSamples := 0
|
|
memoryMean := Mean{count: 0, Mean: 0}
|
|
cpuMean := Mean{count: 0, Mean: 0}
|
|
memoryPercentiles := Percentiles{}
|
|
cpuPercentiles := Percentiles{}
|
|
for _, stat := range stats {
|
|
var elapsed int64
|
|
time := stat.Timestamp
|
|
if !lastTime.IsZero() {
|
|
elapsed = time.UnixNano() - lastTime.UnixNano()
|
|
if elapsed < 10*milliSecondsToNanoSeconds {
|
|
glog.Infof("Elapsed time too small: %d ns: time now %s last %s", elapsed, time.String(), lastTime.String())
|
|
continue
|
|
}
|
|
}
|
|
numSamples++
|
|
cpuNs := stat.Cpu.Usage.Total
|
|
// Ignore actual usage and only focus on working set.
|
|
memory := stat.Memory.WorkingSet
|
|
if memory > memoryPercentiles.Max {
|
|
memoryPercentiles.Max = memory
|
|
}
|
|
glog.V(2).Infof("Read sample: cpu %d, memory %d", cpuNs, memory)
|
|
memoryMean.Add(memory)
|
|
memorySamples = append(memorySamples, memory)
|
|
if lastTime.IsZero() {
|
|
lastCpu = cpuNs
|
|
lastTime = time
|
|
continue
|
|
}
|
|
cpuRate := (cpuNs - lastCpu) * secondsToMilliSeconds / uint64(elapsed)
|
|
if cpuRate < 0 {
|
|
glog.Infof("cpu rate too small: %f ns", cpuRate)
|
|
continue
|
|
}
|
|
glog.V(2).Infof("Adding cpu rate sample : %d", cpuRate)
|
|
lastCpu = cpuNs
|
|
lastTime = time
|
|
cpuSamples = append(cpuSamples, cpuRate)
|
|
if cpuRate > cpuPercentiles.Max {
|
|
cpuPercentiles.Max = cpuRate
|
|
}
|
|
cpuMean.Add(cpuRate)
|
|
}
|
|
cpuPercentiles.Mean = uint64(cpuMean.Mean)
|
|
memoryPercentiles.Mean = uint64(memoryMean.Mean)
|
|
cpuPercentiles.Ninety = cpuSamples.Get90Percentile()
|
|
memoryPercentiles.Ninety = memorySamples.Get90Percentile()
|
|
return cpuPercentiles, memoryPercentiles
|
|
}
|