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 {
|
type CpuStats struct {
|
||||||
Usage 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"`
|
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"`
|
} `json:"usage"`
|
||||||
Load int32 `json:"load"`
|
Load int32 `json:"load"`
|
||||||
}
|
}
|
||||||
@ -142,6 +154,18 @@ type ContainerStats struct {
|
|||||||
Memory *MemoryStats `json:"memory,omitempty"`
|
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.
|
// This is not exported.
|
||||||
// Use FillPercentile to calculate percentiles
|
// Use FillPercentile to calculate percentiles
|
||||||
type percentile struct {
|
type percentile struct {
|
||||||
@ -151,11 +175,37 @@ type percentile struct {
|
|||||||
|
|
||||||
type ContainerStatsSummary struct {
|
type ContainerStatsSummary struct {
|
||||||
// TODO(dengnan): More things?
|
// TODO(dengnan): More things?
|
||||||
MaxMemoryUsage uint64 `json:"max_memory_usage,omitempty"`
|
MaxMemoryUsage uint64 `json:"max_memory_usage,omitempty"`
|
||||||
AvgMemoryUsage uint64 `json:"avg_memory_usage,omitempty"`
|
AvgMemoryUsage uint64 `json:"avg_memory_usage,omitempty"`
|
||||||
Samples []*ContainerStats `json:"samples,omitempty"`
|
Samples []*ContainerStatsSample `json:"samples,omitempty"`
|
||||||
MemoryUsagePercentiles []percentile `json:"memory_usage_percentiles,omitempty"`
|
MemoryUsagePercentiles []percentile `json:"memory_usage_percentiles,omitempty"`
|
||||||
CpuUsagePercentiles []percentile `json:"cpu_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
|
type uint64Slice []uint64
|
||||||
@ -190,7 +240,7 @@ func (self uint64Slice) Percentiles(ps ...int) []uint64 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// len(bs) <= len(as)
|
// len(bs) <= len(as)
|
||||||
func float64Zipuint64(as []int, bs []uint64) []percentile {
|
func intZipuint64(as []int, bs []uint64) []percentile {
|
||||||
if len(bs) == 0 {
|
if len(bs) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -216,16 +266,12 @@ func (self *ContainerStatsSummary) FillPercentiles(cpuPercentages, memoryPercent
|
|||||||
if sample == nil {
|
if sample == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if sample.Cpu != nil {
|
cpuUsages = append(cpuUsages, sample.Cpu.Usage)
|
||||||
cpuUsages = append(cpuUsages, sample.Cpu.Usage.Total)
|
memUsages = append(memUsages, sample.Memory.Usage)
|
||||||
}
|
|
||||||
if sample.Memory != nil {
|
|
||||||
memUsages = append(memUsages, sample.Memory.Usage)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cpuPercentiles := uint64Slice(cpuUsages).Percentiles(cpuPercentages...)
|
cpuPercentiles := uint64Slice(cpuUsages).Percentiles(cpuPercentages...)
|
||||||
memPercentiles := uint64Slice(memUsages).Percentiles(memoryPercentages...)
|
memPercentiles := uint64Slice(memUsages).Percentiles(memoryPercentages...)
|
||||||
self.CpuUsagePercentiles = float64Zipuint64(cpuPercentages, cpuPercentiles)
|
self.CpuUsagePercentiles = intZipuint64(cpuPercentages, cpuPercentiles)
|
||||||
self.MemoryUsagePercentiles = float64Zipuint64(memoryPercentages, memPercentiles)
|
self.MemoryUsagePercentiles = intZipuint64(memoryPercentages, memPercentiles)
|
||||||
}
|
}
|
||||||
|
@ -70,17 +70,17 @@ func TestPercentiles(t *testing.T) {
|
|||||||
for i := 0; i < N; i++ {
|
for i := 0; i < N; i++ {
|
||||||
data[i] = uint64(i)
|
data[i] = uint64(i)
|
||||||
}
|
}
|
||||||
ps := []float64{
|
ps := []int{
|
||||||
0.8,
|
80,
|
||||||
0.9,
|
90,
|
||||||
0.5,
|
50,
|
||||||
}
|
}
|
||||||
ss := uint64Slice(data).Percentiles(ps...)
|
ss := uint64Slice(data).Percentiles(ps...)
|
||||||
for i, s := range ss {
|
for i, s := range ss {
|
||||||
p := ps[i]
|
p := ps[i]
|
||||||
d := uint64(float64(N) * p)
|
d := uint64(float64(N) * (float64(p) / 100.0))
|
||||||
if d != s {
|
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