unit test for sampling
This commit is contained in:
parent
205a379887
commit
478ff3d45e
@ -67,7 +67,10 @@ func (self *statsSummaryContainerHandlerWrapper) GetStats() (*info.ContainerStat
|
|||||||
if stats == nil {
|
if stats == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
stats.Timestamp = time.Now()
|
// Only update timestamp if it is zero.
|
||||||
|
if stats.Timestamp.IsZero() {
|
||||||
|
stats.Timestamp = time.Now()
|
||||||
|
}
|
||||||
self.lock.Lock()
|
self.lock.Lock()
|
||||||
defer self.lock.Unlock()
|
defer self.lock.Unlock()
|
||||||
|
|
||||||
|
@ -18,7 +18,9 @@ import (
|
|||||||
crand "crypto/rand"
|
crand "crypto/rand"
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/google/cadvisor/info"
|
"github.com/google/cadvisor/info"
|
||||||
)
|
)
|
||||||
@ -31,13 +33,28 @@ func init() {
|
|||||||
rand.Seed(seed)
|
rand.Seed(seed)
|
||||||
}
|
}
|
||||||
|
|
||||||
type randomMemoryUsageContainer struct {
|
type notARealContainer struct {
|
||||||
NoStatsSummary
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *randomMemoryUsageContainer) GetSpec() (*info.ContainerSpec, error) {
|
func (self *notARealContainer) GetSpec() (*info.ContainerSpec, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
func (self *notARealContainer) ListContainers(listType ListType) ([]string, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *notARealContainer) ListThreads(listType ListType) ([]int, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *notARealContainer) ListProcesses(listType ListType) ([]int, error) {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type randomMemoryUsageContainer struct {
|
||||||
|
NoStatsSummary
|
||||||
|
notARealContainer
|
||||||
|
}
|
||||||
|
|
||||||
func (self *randomMemoryUsageContainer) GetStats() (*info.ContainerStats, error) {
|
func (self *randomMemoryUsageContainer) GetStats() (*info.ContainerStats, error) {
|
||||||
stats := new(info.ContainerStats)
|
stats := new(info.ContainerStats)
|
||||||
@ -47,18 +64,6 @@ func (self *randomMemoryUsageContainer) GetStats() (*info.ContainerStats, error)
|
|||||||
return stats, nil
|
return stats, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *randomMemoryUsageContainer) ListContainers(listType ListType) ([]string, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *randomMemoryUsageContainer) ListThreads(listType ListType) ([]int, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *randomMemoryUsageContainer) ListProcesses(listType ListType) ([]int, error) {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestAvgMaxMemoryUsage(t *testing.T) {
|
func TestAvgMaxMemoryUsage(t *testing.T) {
|
||||||
handler, err := AddStatsSummary(
|
handler, err := AddStatsSummary(
|
||||||
&randomMemoryUsageContainer{},
|
&randomMemoryUsageContainer{},
|
||||||
@ -96,3 +101,100 @@ func TestAvgMaxMemoryUsage(t *testing.T) {
|
|||||||
t.Fatalf("Avg memory usage should be %v; received %v", avg, summary.AvgMemoryUsage)
|
t.Fatalf("Avg memory usage should be %v; received %v", avg, summary.AvgMemoryUsage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type replayCpuTrace struct {
|
||||||
|
NoStatsSummary
|
||||||
|
notARealContainer
|
||||||
|
cpuTrace []uint64
|
||||||
|
totalUsage uint64
|
||||||
|
currenttime time.Time
|
||||||
|
duration time.Duration
|
||||||
|
lock sync.Mutex
|
||||||
|
}
|
||||||
|
|
||||||
|
func containerWithCpuTrace(duration time.Duration, cpuUsages ...uint64) ContainerHandler {
|
||||||
|
return &replayCpuTrace{
|
||||||
|
duration: duration,
|
||||||
|
cpuTrace: cpuUsages,
|
||||||
|
currenttime: time.Now(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *replayCpuTrace) GetStats() (*info.ContainerStats, error) {
|
||||||
|
stats := new(info.ContainerStats)
|
||||||
|
stats.Cpu = new(info.CpuStats)
|
||||||
|
stats.Memory = new(info.MemoryStats)
|
||||||
|
stats.Memory.Usage = uint64(rand.Intn(2048))
|
||||||
|
|
||||||
|
self.lock.Lock()
|
||||||
|
defer self.lock.Unlock()
|
||||||
|
|
||||||
|
cpuTrace := self.totalUsage
|
||||||
|
if len(self.cpuTrace) > 0 {
|
||||||
|
cpuTrace += self.cpuTrace[0]
|
||||||
|
self.cpuTrace = self.cpuTrace[1:]
|
||||||
|
}
|
||||||
|
self.totalUsage = cpuTrace
|
||||||
|
stats.Timestamp = self.currenttime
|
||||||
|
self.currenttime = self.currenttime.Add(self.duration)
|
||||||
|
stats.Cpu.Usage.Total = cpuTrace
|
||||||
|
stats.Cpu.Usage.PerCpu = []uint64{cpuTrace}
|
||||||
|
stats.Cpu.Usage.User = cpuTrace
|
||||||
|
stats.Cpu.Usage.System = 0
|
||||||
|
return stats, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSampleCpuUsage(t *testing.T) {
|
||||||
|
// Number of samples
|
||||||
|
N := 10
|
||||||
|
cpuTrace := make([]uint64, 0, N)
|
||||||
|
|
||||||
|
// We need N+1 observations to get N samples
|
||||||
|
for i := 0; i < N+1; i++ {
|
||||||
|
usage := uint64(rand.Intn(1000))
|
||||||
|
cpuTrace = append(cpuTrace, usage)
|
||||||
|
}
|
||||||
|
|
||||||
|
samplePeriod := 1 * time.Second
|
||||||
|
|
||||||
|
handler, err := AddStatsSummary(
|
||||||
|
containerWithCpuTrace(samplePeriod, cpuTrace...),
|
||||||
|
&StatsParameter{
|
||||||
|
// Use uniform sampler with sample size of N, so that
|
||||||
|
// we will be guaranteed to store the first N samples.
|
||||||
|
Sampler: "uniform",
|
||||||
|
NumSamples: N,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// request stats/obervation N+1 times, so that there will be N samples
|
||||||
|
for i := 0; i < N+1; i++ {
|
||||||
|
_, err = handler.GetStats()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s, err := handler.StatsSummary()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
for _, sample := range s.Samples {
|
||||||
|
if sample.Duration != samplePeriod {
|
||||||
|
t.Errorf("sample duration is %v, not %v", sample.Duration, samplePeriod)
|
||||||
|
}
|
||||||
|
cpuUsage := sample.Cpu.Usage
|
||||||
|
found := false
|
||||||
|
for _, u := range cpuTrace {
|
||||||
|
if u == cpuUsage {
|
||||||
|
found = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !found {
|
||||||
|
t.Errorf("unable to find cpu usage %v", cpuUsage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -156,8 +156,11 @@ type ContainerStats struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ContainerStatsSample struct {
|
type ContainerStatsSample struct {
|
||||||
|
// Timetamp of the end of the sample period
|
||||||
Timestamp time.Time `json:"timestamp"`
|
Timestamp time.Time `json:"timestamp"`
|
||||||
Cpu struct {
|
// Duration of the sample period
|
||||||
|
Duration time.Duration `json:"duration"`
|
||||||
|
Cpu struct {
|
||||||
// number of nanoseconds of CPU time used by the container
|
// number of nanoseconds of CPU time used by the container
|
||||||
// within one second.
|
// within one second.
|
||||||
Usage uint64 `json:"usage"`
|
Usage uint64 `json:"usage"`
|
||||||
@ -206,6 +209,7 @@ func NewSample(prev, current *ContainerStats) (*ContainerStatsSample, error) {
|
|||||||
// Memory usage is current memory usage
|
// Memory usage is current memory usage
|
||||||
sample.Memory.Usage = current.Memory.Usage
|
sample.Memory.Usage = current.Memory.Usage
|
||||||
sample.Timestamp = current.Timestamp
|
sample.Timestamp = current.Timestamp
|
||||||
|
sample.Duration = current.Timestamp.Sub(prev.Timestamp)
|
||||||
|
|
||||||
return sample, nil
|
return sample, nil
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user