Merge pull request #509 from rjnagal/summary

Add derived stats tracking to containers.
This commit is contained in:
Victor Marmol 2015-02-16 13:55:50 -08:00
commit 31769a89dd
5 changed files with 40 additions and 8 deletions

View File

@ -52,7 +52,9 @@ func GenerateRandomStats(numStats, numCores int, duration time.Duration) []*info
func GenerateRandomContainerSpec(numCores int) info.ContainerSpec { func GenerateRandomContainerSpec(numCores int) info.ContainerSpec {
ret := info.ContainerSpec{ ret := info.ContainerSpec{
CreationTime: time.Now(), CreationTime: time.Now(),
HasCpu: true,
Cpu: info.CpuSpec{}, Cpu: info.CpuSpec{},
HasMemory: true,
Memory: info.MemorySpec{}, Memory: info.MemorySpec{},
} }
ret.Cpu.Limit = uint64(1000 + rand.Int63n(2000)) ret.Cpu.Limit = uint64(1000 + rand.Int63n(2000))

View File

@ -26,6 +26,7 @@ import (
"github.com/google/cadvisor/container" "github.com/google/cadvisor/container"
"github.com/google/cadvisor/info" "github.com/google/cadvisor/info"
"github.com/google/cadvisor/storage" "github.com/google/cadvisor/storage"
"github.com/google/cadvisor/summary"
"github.com/google/cadvisor/utils/cpuload" "github.com/google/cadvisor/utils/cpuload"
) )
@ -49,6 +50,7 @@ type containerData struct {
storageDriver storage.StorageDriver storageDriver storage.StorageDriver
lock sync.Mutex lock sync.Mutex
loadReader cpuload.CpuLoadReader loadReader cpuload.CpuLoadReader
summaryReader *summary.StatsSummary
loadAvg float64 // smoothed load average seen so far. loadAvg float64 // smoothed load average seen so far.
housekeepingInterval time.Duration housekeepingInterval time.Duration
lastUpdatedTime time.Time lastUpdatedTime time.Time
@ -121,6 +123,15 @@ func newContainerData(containerName string, driver storage.StorageDriver, handle
} }
cont.info.ContainerReference = ref cont.info.ContainerReference = ref
err = cont.updateSpec()
if err != nil {
return nil, err
}
cont.summaryReader, err = summary.New(cont.info.Spec)
if err != nil {
return nil, fmt.Errorf("failed to create summary reader: %v", err)
}
return cont, nil return cont, nil
} }
@ -278,6 +289,13 @@ func (c *containerData) updateStats() error {
stats.Cpu.LoadAverage = int32(c.loadAvg * 1000) stats.Cpu.LoadAverage = int32(c.loadAvg * 1000)
} }
} }
if c.summaryReader != nil {
err := c.summaryReader.AddSample(*stats)
if err != nil {
// Ignore summary errors for now.
glog.V(2).Infof("failed to add summary stats for %q: %v", c.info.Name, err)
}
}
ref, err := c.handler.ContainerReference() ref, err := c.handler.ContainerReference()
if err != nil { if err != nil {
// Ignore errors if the container is dead. // Ignore errors if the container is dead.

View File

@ -31,9 +31,13 @@ import (
const containerName = "/container" const containerName = "/container"
// Create a containerData instance for a test. Optionsl storage driver may be specified (one is made otherwise). // Create a containerData instance for a test.
func newTestContainerData(t *testing.T) (*containerData, *container.MockContainerHandler, *stest.MockStorageDriver) { func setupContainerData(t *testing.T, spec info.ContainerSpec) (*containerData, *container.MockContainerHandler, *stest.MockStorageDriver) {
mockHandler := container.NewMockContainerHandler(containerName) mockHandler := container.NewMockContainerHandler(containerName)
mockHandler.On("GetSpec").Return(
spec,
nil,
)
mockDriver := &stest.MockStorageDriver{} mockDriver := &stest.MockStorageDriver{}
ret, err := newContainerData(containerName, mockDriver, mockHandler, nil, false) ret, err := newContainerData(containerName, mockDriver, mockHandler, nil, false)
if err != nil { if err != nil {
@ -42,6 +46,13 @@ func newTestContainerData(t *testing.T) (*containerData, *container.MockContaine
return ret, mockHandler, mockDriver return ret, mockHandler, mockDriver
} }
// Create a containerData instance for a test and add a default GetSpec mock.
func newTestContainerData(t *testing.T) (*containerData, *container.MockContainerHandler, *stest.MockStorageDriver) {
spec := itest.GenerateRandomContainerSpec(4)
ret, mockHandler, mockDriver := setupContainerData(t, spec)
return ret, mockHandler, mockDriver
}
func TestUpdateSubcontainers(t *testing.T) { func TestUpdateSubcontainers(t *testing.T) {
subcontainers := []info.ContainerReference{ subcontainers := []info.ContainerReference{
{Name: "/container/ee0103"}, {Name: "/container/ee0103"},
@ -146,11 +157,7 @@ func TestGetInfo(t *testing.T) {
{Name: "/container/abcd"}, {Name: "/container/abcd"},
{Name: "/container/something"}, {Name: "/container/something"},
} }
cd, mockHandler, _ := newTestContainerData(t) cd, mockHandler, _ := setupContainerData(t, spec)
mockHandler.On("GetSpec").Return(
spec,
nil,
)
mockHandler.On("ListContainers", container.ListSelf).Return( mockHandler.On("ListContainers", container.ListSelf).Return(
subcontainers, subcontainers,
nil, nil,

View File

@ -50,6 +50,11 @@ func createManagerAndAddContainers(
if ret, ok := mif.(*manager); ok { if ret, ok := mif.(*manager); ok {
for _, name := range containers { for _, name := range containers {
mockHandler := container.NewMockContainerHandler(name) mockHandler := container.NewMockContainerHandler(name)
spec := itest.GenerateRandomContainerSpec(4)
mockHandler.On("GetSpec").Return(
spec,
nil,
).Once()
cont, err := newContainerData(name, driver, mockHandler, nil, false) cont, err := newContainerData(name, driver, mockHandler, nil, false)
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)

View File

@ -45,7 +45,7 @@ func (self uint64Slice) Get90Percentile() uint64 {
idx, frac := math.Modf(n) idx, frac := math.Modf(n)
index := int(idx) index := int(idx)
percentile := float64(self[index-1]) percentile := float64(self[index-1])
if index > 1 || index < count { if index > 1 && index < count {
percentile += frac * float64(self[index]-self[index-1]) percentile += frac * float64(self[index]-self[index-1])
} }
return uint64(percentile) return uint64(percentile)