Use ContainerStatsSample to store samples because CPU usages are
cumilative
This commit is contained in:
parent
d5f9cbc890
commit
eaa166e8c3
@ -101,10 +101,22 @@ func (self *ContainerInfo) StatsEndTime() time.Time {
|
||||
|
||||
type CpuStats struct {
|
||||
Usage struct {
|
||||
Total uint64 `json:"total"`
|
||||
// Number of nanoseconds of CPU time used by the container
|
||||
// since the beginning. This is a ccumulative
|
||||
// value, not an instantaneous value.
|
||||
Total uint64 `json:"total"`
|
||||
|
||||
// Per CPU/core usage of the container.
|
||||
// Unit: nanoseconds.
|
||||
PerCpu []uint64 `json:"per_cpu,omitempty"`
|
||||
User uint64 `json:"user"`
|
||||
System uint64 `json:"system"`
|
||||
|
||||
// How much time was spent in user space since beginning.
|
||||
// Unit: nanoseconds
|
||||
User uint64 `json:"user"`
|
||||
|
||||
// How much time was spent in kernel space since beginning.
|
||||
// Unit: nanoseconds
|
||||
System uint64 `json:"system"`
|
||||
} `json:"usage"`
|
||||
Load int32 `json:"load"`
|
||||
}
|
||||
@ -142,6 +154,18 @@ type ContainerStats struct {
|
||||
Memory *MemoryStats `json:"memory,omitempty"`
|
||||
}
|
||||
|
||||
type ContainerStatsSample struct {
|
||||
Cpu struct {
|
||||
// number of nanoseconds of CPU time used by the container
|
||||
// within one second.
|
||||
Usage uint64 `json:"usage"`
|
||||
} `json:"cpu"`
|
||||
Memory struct {
|
||||
// Units: Bytes.
|
||||
Usage uint64 `json:"usage"`
|
||||
} `json:"memory"`
|
||||
}
|
||||
|
||||
// This is not exported.
|
||||
// Use FillPercentile to calculate percentiles
|
||||
type percentile struct {
|
||||
@ -151,11 +175,37 @@ type percentile struct {
|
||||
|
||||
type ContainerStatsSummary struct {
|
||||
// TODO(dengnan): More things?
|
||||
MaxMemoryUsage uint64 `json:"max_memory_usage,omitempty"`
|
||||
AvgMemoryUsage uint64 `json:"avg_memory_usage,omitempty"`
|
||||
Samples []*ContainerStats `json:"samples,omitempty"`
|
||||
MemoryUsagePercentiles []percentile `json:"memory_usage_percentiles,omitempty"`
|
||||
CpuUsagePercentiles []percentile `json:"cpu_usage_percentiles,omitempty"`
|
||||
MaxMemoryUsage uint64 `json:"max_memory_usage,omitempty"`
|
||||
AvgMemoryUsage uint64 `json:"avg_memory_usage,omitempty"`
|
||||
Samples []*ContainerStatsSample `json:"samples,omitempty"`
|
||||
MemoryUsagePercentiles []percentile `json:"memory_usage_percentiles,omitempty"`
|
||||
CpuUsagePercentiles []percentile `json:"cpu_usage_percentiles,omitempty"`
|
||||
}
|
||||
|
||||
// Each sample needs two stats because the cpu usage in ContainerStats is
|
||||
// cumulative.
|
||||
// prev should be an earlier observation than current.
|
||||
// This method is not thread/goroutine safe.
|
||||
func (self *ContainerStatsSummary) AddSample(prev, current *ContainerStats) {
|
||||
if prev == nil || current == nil {
|
||||
return
|
||||
}
|
||||
// Ignore this sample if it is incomplete
|
||||
if prev.Cpu == nil || prev.Memory == nil || current.Cpu == nil || current.Memory == nil {
|
||||
return
|
||||
}
|
||||
// prev must be an early observation
|
||||
if !current.Timestamp.After(prev.Timestamp) {
|
||||
return
|
||||
}
|
||||
sample := new(ContainerStatsSample)
|
||||
// Caculate the diff to get the CPU usage within the time interval.
|
||||
sample.Cpu.Usage = current.Cpu.Usage.Total - prev.Cpu.Usage.Total
|
||||
// Memory usage is current memory usage
|
||||
sample.Memory.Usage = current.Memory.Usage
|
||||
|
||||
self.Samples = append(self.Samples, sample)
|
||||
return
|
||||
}
|
||||
|
||||
type uint64Slice []uint64
|
||||
@ -190,7 +240,7 @@ func (self uint64Slice) Percentiles(ps ...int) []uint64 {
|
||||
}
|
||||
|
||||
// len(bs) <= len(as)
|
||||
func float64Zipuint64(as []int, bs []uint64) []percentile {
|
||||
func intZipuint64(as []int, bs []uint64) []percentile {
|
||||
if len(bs) == 0 {
|
||||
return nil
|
||||
}
|
||||
@ -216,16 +266,12 @@ func (self *ContainerStatsSummary) FillPercentiles(cpuPercentages, memoryPercent
|
||||
if sample == nil {
|
||||
continue
|
||||
}
|
||||
if sample.Cpu != nil {
|
||||
cpuUsages = append(cpuUsages, sample.Cpu.Usage.Total)
|
||||
}
|
||||
if sample.Memory != nil {
|
||||
memUsages = append(memUsages, sample.Memory.Usage)
|
||||
}
|
||||
cpuUsages = append(cpuUsages, sample.Cpu.Usage)
|
||||
memUsages = append(memUsages, sample.Memory.Usage)
|
||||
}
|
||||
|
||||
cpuPercentiles := uint64Slice(cpuUsages).Percentiles(cpuPercentages...)
|
||||
memPercentiles := uint64Slice(memUsages).Percentiles(memoryPercentages...)
|
||||
self.CpuUsagePercentiles = float64Zipuint64(cpuPercentages, cpuPercentiles)
|
||||
self.MemoryUsagePercentiles = float64Zipuint64(memoryPercentages, memPercentiles)
|
||||
self.CpuUsagePercentiles = intZipuint64(cpuPercentages, cpuPercentiles)
|
||||
self.MemoryUsagePercentiles = intZipuint64(memoryPercentages, memPercentiles)
|
||||
}
|
||||
|
@ -70,17 +70,17 @@ func TestPercentiles(t *testing.T) {
|
||||
for i := 0; i < N; i++ {
|
||||
data[i] = uint64(i)
|
||||
}
|
||||
ps := []float64{
|
||||
0.8,
|
||||
0.9,
|
||||
0.5,
|
||||
ps := []int{
|
||||
80,
|
||||
90,
|
||||
50,
|
||||
}
|
||||
ss := uint64Slice(data).Percentiles(ps...)
|
||||
for i, s := range ss {
|
||||
p := ps[i]
|
||||
d := uint64(float64(N) * p)
|
||||
d := uint64(float64(N) * (float64(p) / 100.0))
|
||||
if d != s {
|
||||
t.Errorf("%v \\%tile data should be %v, but got %v", p*float64(100), d, s)
|
||||
t.Errorf("%v \\%tile data should be %v, but got %v", float64(p)/100.0, d, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user