-
-
-
-
-
- {{range $parentContainer := .ParentContainers}}
- - {{containerLink $parentContainer true ""}}
- {{end}}
-
-
- {{if .Subcontainers}}
-
-
-
- {{range $subcontainer := .Subcontainers}}
- {{containerLink $subcontainer false "list-group-item"}}
+
+
+
+
+
+
+
+
+
+ {{range $parentContainer := .ParentContainers}}
+ - {{containerLink $parentContainer true ""}}
+ {{end}}
+
+
+ {{if .Subcontainers}}
+
+
+
+ {{range $subcontainer := .Subcontainers}}
+ {{containerLink $subcontainer false "list-group-item"}}
+ {{end}}
+
+
+ {{end}}
+ {{if .ResourcesAvailable}}
+
+
+ {{if .CpuAvailable}}
+
+ - CPU
+ {{if .Spec.Cpu.Limit}}
+ - Shares {{printShares .Spec.Cpu.Limit}} shares
+ {{end}}
+ {{if .Spec.Cpu.MaxLimit}}
+ - Max Limit {{printCores .Spec.Cpu.MaxLimit}} cores
+ {{end}}
+ {{if .Spec.Cpu.Mask}}
+ - Allowed Cores {{printMask .Spec.Cpu.Mask .MachineInfo.NumCores}}
+ {{end}}
+
+ {{end}}
+ {{if .MemoryAvailable}}
+
+ - Memory
+ {{if .Spec.Memory.Reservation}}
+ - Reservation {{printMegabytes .Spec.Memory.Reservation}} MB
+ {{end}}
+ {{if .Spec.Memory.Limit}}
+ - Limit {{printMegabytes .Spec.Memory.Limit}} MB
+ {{end}}
+ {{if .Spec.Memory.SwapLimit}}
+ - Swap Limit {{printMegabytes .Spec.Memory.SwapLimit}} MB
+ {{end}}
+
+ {{end}}
+
+
+
+
+ {{if .CpuAvailable}}
+
+
+
CPU
+
+
+
Total Usage
+
+
Usage per Core
+
+
Usage Breakdown
+
+
+
+ {{end}}
+ {{if .MemoryAvailable}}
+
+
+
Memory
+
+
+
Total Usage
+
+
+
+
Usage Breakdown
+
+
+
+ Hot Memory
+
+
+ Cold Memory
+
+
+
+
+ {{ getMemoryUsage .Stats }} MB ({{ getMemoryUsagePercent .Spec .Stats .MachineInfo}}%)
+
+
+
Page Faults
+
+
+
+ {{end}}
+ {{if .NetworkAvailable}}
+
+ {{end}}
+
{{end}}
-
- {{end}}
- {{if .ResourcesAvailable}}
-
-
- {{if .CpuAvailable}}
-
- - CPU
- {{if .Spec.Cpu.Limit}}
- - Limit {{printCores .Spec.Cpu.Limit}} cores
- {{end}}
- {{if .Spec.Cpu.MaxLimit}}
- - Max Limit {{printCores .Spec.Cpu.MaxLimit}} cores
- {{end}}
- {{if .Spec.Cpu.Mask}}
- - Allowed Cores {{printMask .Spec.Cpu.Mask .MachineInfo.NumCores}}
- {{end}}
-
- {{end}}
- {{if .MemoryAvailable}}
-
- - Memory
- {{if .Spec.Memory.Reservation}}
- - Reservation {{printMegabytes .Spec.Memory.Reservation}} MB
- {{end}}
- {{if .Spec.Memory.Limit}}
- - Limit {{printMegabytes .Spec.Memory.Limit}} MB
- {{end}}
- {{if .Spec.Memory.SwapLimit}}
- - Swap Limit {{printMegabytes .Spec.Memory.SwapLimit}} MB
- {{end}}
-
- {{end}}
-
-
-
-
- {{if .CpuAvailable}}
-
-
-
CPU
-
-
-
Total Usage
-
-
Usage per Core
-
-
Usage Breakdown
-
-
-
- {{end}}
- {{if .MemoryAvailable}}
-
-
-
Memory
-
-
-
Total Usage
-
-
-
-
Usage Breakdown
-
-
-
- Hot Memory
-
-
- Cold Memory
-
-
-
-
- {{ getMemoryUsage .Stats }} MB ({{ getMemoryUsagePercent .Spec .Stats .MachineInfo}}%)
-
-
-
Page Faults
-
-
-
- {{end}}
-
- {{end}}
-
-
-
+
+
`
diff --git a/third_party/src/github.com/google/cadvisor/pages/static/containers_js.go b/third_party/src/github.com/google/cadvisor/pages/static/containers_js.go
index 086c610b8f9..0858d5e104b 100644
--- a/third_party/src/github.com/google/cadvisor/pages/static/containers_js.go
+++ b/third_party/src/github.com/google/cadvisor/pages/static/containers_js.go
@@ -90,9 +90,14 @@ function getMachineInfo(callback) {
// Get the container stats for the specified container.
function getStats(containerName, callback) {
- $.getJSON("/api/v1.0/containers" + containerName, function(data) {
- callback(data);
+ // Request 60s of container history and no samples.
+ var request = JSON.stringify({
+ "num_stats": 60,
+ "num_samples": 0
});
+ $.post("/api/v1.0/containers" + containerName, request, function(data) {
+ callback(data);
+ }, "json");
}
// Draw the graph for CPU usage.
@@ -163,7 +168,7 @@ function drawOverallUsage(elementId, machineInfo, containerInfo) {
var rawUsage = cur.cpu.usage.total - prev.cpu.usage.total;
// Convert to millicores and take the percentage
- cpuUsage = Math.round(((rawUsage / 1000000) / containerInfo.spec.cpu.limit) * 100);
+ cpuUsage = Math.round(((rawUsage / 1000000) / (machineInfo.num_cores * 1000)) * 100);
if (cpuUsage > 100) {
cpuUsage = 100;
}
@@ -219,6 +224,42 @@ function drawMemoryPageFaults(elementId, containerInfo) {
drawLineChart(titles, data, elementId, "Faults");
}
+// Draw the graph for network tx/rx bytes.
+function drawNetworkBytes(elementId, machineInfo, stats) {
+ var titles = ["Time", "Tx bytes", "Rx bytes"];
+ var data = [];
+ for (var i = 1; i < stats.stats.length; i++) {
+ var cur = stats.stats[i];
+ var prev = stats.stats[i - 1];
+
+ // TODO(vmarmol): This assumes we sample every second, use the timestamps.
+ var elements = [];
+ elements.push(cur.timestamp);
+ elements.push(cur.network.tx_bytes - prev.network.tx_bytes);
+ elements.push(cur.network.rx_bytes - prev.network.rx_bytes);
+ data.push(elements);
+ }
+ drawLineChart(titles, data, elementId, "Bytes per second");
+}
+
+// Draw the graph for network errors
+function drawNetworkErrors(elementId, machineInfo, stats) {
+ var titles = ["Time", "Tx", "Rx"];
+ var data = [];
+ for (var i = 1; i < stats.stats.length; i++) {
+ var cur = stats.stats[i];
+ var prev = stats.stats[i - 1];
+
+ // TODO(vmarmol): This assumes we sample every second, use the timestamps.
+ var elements = [];
+ elements.push(cur.timestamp);
+ elements.push(cur.network.tx_errors - prev.network.tx_errors);
+ elements.push(cur.network.rx_errors - prev.network.rx_errors);
+ data.push(elements);
+ }
+ drawLineChart(titles, data, elementId, "Errors per second");
+}
+
// Expects an array of closures to call. After each execution the JS runtime is given control back before continuing.
// This function returns asynchronously
function stepExecute(steps) {
@@ -264,6 +305,14 @@ function drawCharts(machineInfo, containerInfo) {
drawMemoryPageFaults("memory-page-faults-chart", containerInfo);
});
+ // Network.
+ steps.push(function() {
+ drawNetworkBytes("network-bytes-chart", machineInfo, containerInfo);
+ });
+ steps.push(function() {
+ drawNetworkErrors("network-errors-chart", machineInfo, containerInfo);
+ });
+
stepExecute(steps);
}
diff --git a/third_party/src/github.com/google/cadvisor/storage/cache/memcache.go b/third_party/src/github.com/google/cadvisor/storage/cache/memcache.go
new file mode 100644
index 00000000000..fdc7d029695
--- /dev/null
+++ b/third_party/src/github.com/google/cadvisor/storage/cache/memcache.go
@@ -0,0 +1,72 @@
+// Copyright 2014 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 cache
+
+import (
+ "github.com/google/cadvisor/info"
+ "github.com/google/cadvisor/storage"
+ "github.com/google/cadvisor/storage/memory"
+)
+
+type cachedStorageDriver struct {
+ maxNumStatsInCache int
+ maxNumSamplesInCache int
+ cache storage.StorageDriver
+ backend storage.StorageDriver
+}
+
+func (self *cachedStorageDriver) AddStats(ref info.ContainerReference, stats *info.ContainerStats) error {
+ err := self.cache.AddStats(ref, stats)
+ if err != nil {
+ return err
+ }
+ err = self.backend.AddStats(ref, stats)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func (self *cachedStorageDriver) RecentStats(containerName string, numStats int) ([]*info.ContainerStats, error) {
+ if numStats < self.maxNumStatsInCache {
+ return self.cache.RecentStats(containerName, numStats)
+ }
+ return self.backend.RecentStats(containerName, numStats)
+}
+
+func (self *cachedStorageDriver) Percentiles(containerName string, cpuUsagePercentiles []int, memUsagePercentiles []int) (*info.ContainerStatsPercentiles, error) {
+ return self.backend.Percentiles(containerName, cpuUsagePercentiles, memUsagePercentiles)
+}
+
+func (self *cachedStorageDriver) Samples(containerName string, numSamples int) ([]*info.ContainerStatsSample, error) {
+ if numSamples < self.maxNumSamplesInCache {
+ return self.cache.Samples(containerName, numSamples)
+ }
+ return self.backend.Samples(containerName, numSamples)
+}
+
+func (self *cachedStorageDriver) Close() error {
+ self.cache.Close()
+ return self.backend.Close()
+}
+
+func MemoryCache(maxNumSamplesInCache, maxNumStatsInCache int, driver storage.StorageDriver) storage.StorageDriver {
+ return &cachedStorageDriver{
+ maxNumStatsInCache: maxNumStatsInCache,
+ maxNumSamplesInCache: maxNumSamplesInCache,
+ cache: memory.New(maxNumSamplesInCache, maxNumStatsInCache),
+ backend: driver,
+ }
+}
diff --git a/third_party/src/github.com/google/cadvisor/storage/cache/memcache_test.go b/third_party/src/github.com/google/cadvisor/storage/cache/memcache_test.go
new file mode 100644
index 00000000000..f77232dfed3
--- /dev/null
+++ b/third_party/src/github.com/google/cadvisor/storage/cache/memcache_test.go
@@ -0,0 +1,78 @@
+// Copyright 2014 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 cache
+
+import (
+ "testing"
+
+ "github.com/google/cadvisor/storage"
+ "github.com/google/cadvisor/storage/memory"
+ "github.com/google/cadvisor/storage/test"
+)
+
+func runStorageTest(f func(storage.StorageDriver, *testing.T), t *testing.T) {
+ maxSize := 200
+
+ var driver storage.StorageDriver
+ for N := 10; N < maxSize; N += 10 {
+ backend := memory.New(N*2, N*2)
+ driver = MemoryCache(N, N, backend)
+ f(driver, t)
+ }
+
+}
+
+func TestMaxMemoryUsage(t *testing.T) {
+ runStorageTest(test.StorageDriverTestMaxMemoryUsage, t)
+}
+
+func TestSampleCpuUsage(t *testing.T) {
+ runStorageTest(test.StorageDriverTestSampleCpuUsage, t)
+}
+
+func TestSamplesWithoutSample(t *testing.T) {
+ runStorageTest(test.StorageDriverTestSamplesWithoutSample, t)
+}
+
+func TestPercentilesWithoutSample(t *testing.T) {
+ runStorageTest(test.StorageDriverTestPercentilesWithoutSample, t)
+}
+
+func TestPercentiles(t *testing.T) {
+ N := 100
+ backend := memory.New(N*2, N*2)
+ driver := MemoryCache(N, N, backend)
+ test.StorageDriverTestPercentiles(driver, t)
+}
+
+func TestRetrievePartialRecentStats(t *testing.T) {
+ runStorageTest(test.StorageDriverTestRetrievePartialRecentStats, t)
+}
+
+func TestRetrieveAllRecentStats(t *testing.T) {
+ runStorageTest(test.StorageDriverTestRetrieveAllRecentStats, t)
+}
+
+func TestNoRecentStats(t *testing.T) {
+ runStorageTest(test.StorageDriverTestNoRecentStats, t)
+}
+
+func TestNoSamples(t *testing.T) {
+ runStorageTest(test.StorageDriverTestNoSamples, t)
+}
+
+func TestPercentilesWithoutStats(t *testing.T) {
+ runStorageTest(test.StorageDriverTestPercentilesWithoutStats, t)
+}
diff --git a/third_party/src/github.com/google/cadvisor/storage/influxdb/influxdb.go b/third_party/src/github.com/google/cadvisor/storage/influxdb/influxdb.go
index 99cb92c718f..d9b38644469 100644
--- a/third_party/src/github.com/google/cadvisor/storage/influxdb/influxdb.go
+++ b/third_party/src/github.com/google/cadvisor/storage/influxdb/influxdb.go
@@ -22,7 +22,7 @@ import (
"github.com/google/cadvisor/info"
"github.com/google/cadvisor/storage"
- "github.com/influxdb/influxdb-go"
+ influxdb "github.com/influxdb/influxdb/client"
)
type influxdbStorage struct {
@@ -320,6 +320,9 @@ func (self *influxdbStorage) AddStats(ref info.ContainerReference, stats *info.C
}
func (self *influxdbStorage) RecentStats(containerName string, numStats int) ([]*info.ContainerStats, error) {
+ if numStats == 0 {
+ return nil, nil
+ }
// TODO(dengnan): select only columns that we need
// TODO(dengnan): escape names
query := fmt.Sprintf("select * from %v where %v='%v' and %v='%v'", self.tableName, colContainerName, containerName, colMachineName, self.machineName)
@@ -352,6 +355,9 @@ func (self *influxdbStorage) RecentStats(containerName string, numStats int) ([]
}
func (self *influxdbStorage) Samples(containerName string, numSamples int) ([]*info.ContainerStatsSample, error) {
+ if numSamples == 0 {
+ return nil, nil
+ }
// TODO(dengnan): select only columns that we need
// TODO(dengnan): escape names
query := fmt.Sprintf("select * from %v where %v='%v' and %v='%v'", self.tableName, colContainerName, containerName, colMachineName, self.machineName)
diff --git a/third_party/src/github.com/google/cadvisor/storage/influxdb/influxdb_test.go b/third_party/src/github.com/google/cadvisor/storage/influxdb/influxdb_test.go
index c5770d35d1b..4605fa56d9c 100644
--- a/third_party/src/github.com/google/cadvisor/storage/influxdb/influxdb_test.go
+++ b/third_party/src/github.com/google/cadvisor/storage/influxdb/influxdb_test.go
@@ -21,7 +21,7 @@ import (
"github.com/google/cadvisor/storage"
"github.com/google/cadvisor/storage/test"
- "github.com/influxdb/influxdb-go"
+ influxdb "github.com/influxdb/influxdb/client"
)
func runStorageTest(f func(storage.StorageDriver, *testing.T), t *testing.T) {
@@ -95,42 +95,64 @@ func runStorageTest(f func(storage.StorageDriver, *testing.T), t *testing.T) {
f(driver, t)
}
+// TODO(vmarmol): Don't skip these tests when Travis is fixed.
+
func TestSampleCpuUsage(t *testing.T) {
+ t.SkipNow()
runStorageTest(test.StorageDriverTestSampleCpuUsage, t)
}
func TestRetrievePartialRecentStats(t *testing.T) {
+ t.SkipNow()
runStorageTest(test.StorageDriverTestRetrievePartialRecentStats, t)
}
func TestSamplesWithoutSample(t *testing.T) {
+ t.SkipNow()
runStorageTest(test.StorageDriverTestSamplesWithoutSample, t)
}
func TestRetrieveAllRecentStats(t *testing.T) {
+ t.SkipNow()
runStorageTest(test.StorageDriverTestRetrieveAllRecentStats, t)
}
func TestNoRecentStats(t *testing.T) {
+ t.SkipNow()
runStorageTest(test.StorageDriverTestNoRecentStats, t)
}
func TestNoSamples(t *testing.T) {
+ t.SkipNow()
runStorageTest(test.StorageDriverTestNoSamples, t)
}
func TestPercentiles(t *testing.T) {
+ t.SkipNow()
runStorageTest(test.StorageDriverTestPercentiles, t)
}
func TestMaxMemoryUsage(t *testing.T) {
+ t.SkipNow()
runStorageTest(test.StorageDriverTestMaxMemoryUsage, t)
}
func TestPercentilesWithoutSample(t *testing.T) {
+ t.SkipNow()
runStorageTest(test.StorageDriverTestPercentilesWithoutSample, t)
}
func TestPercentilesWithoutStats(t *testing.T) {
+ t.SkipNow()
runStorageTest(test.StorageDriverTestPercentilesWithoutStats, t)
}
+
+func TestRetrieveZeroStats(t *testing.T) {
+ t.SkipNow()
+ runStorageTest(test.StorageDriverTestRetrieveZeroRecentStats, t)
+}
+
+func TestRetrieveZeroSamples(t *testing.T) {
+ t.SkipNow()
+ runStorageTest(test.StorageDriverTestRetrieveZeroSamples, t)
+}
diff --git a/third_party/src/github.com/google/cadvisor/storage/memory/memory_test.go b/third_party/src/github.com/google/cadvisor/storage/memory/memory_test.go
index 394e48f6a5f..24b4a7319ba 100644
--- a/third_party/src/github.com/google/cadvisor/storage/memory/memory_test.go
+++ b/third_party/src/github.com/google/cadvisor/storage/memory/memory_test.go
@@ -73,3 +73,11 @@ func TestNoSamples(t *testing.T) {
func TestPercentilesWithoutStats(t *testing.T) {
runStorageTest(test.StorageDriverTestPercentilesWithoutStats, t)
}
+
+func TestRetrieveZeroStats(t *testing.T) {
+ runStorageTest(test.StorageDriverTestRetrieveZeroRecentStats, t)
+}
+
+func TestRetrieveZeroSamples(t *testing.T) {
+ runStorageTest(test.StorageDriverTestRetrieveZeroSamples, t)
+}
diff --git a/third_party/src/github.com/google/cadvisor/storage/test/storagetests.go b/third_party/src/github.com/google/cadvisor/storage/test/storagetests.go
index 8bad2c4d7a9..b9a66f808dc 100644
--- a/third_party/src/github.com/google/cadvisor/storage/test/storagetests.go
+++ b/third_party/src/github.com/google/cadvisor/storage/test/storagetests.go
@@ -482,3 +482,61 @@ func StorageDriverTestPercentilesWithoutStats(driver storage.StorageDriver, t *t
}
}
}
+
+func StorageDriverTestRetrieveZeroRecentStats(driver storage.StorageDriver, t *testing.T) {
+ defer driver.Close()
+ N := 100
+ memTrace := make([]uint64, N)
+ cpuTrace := make([]uint64, N)
+ for i := 0; i < N; i++ {
+ memTrace[i] = uint64(i + 1)
+ cpuTrace[i] = uint64(1)
+ }
+
+ ref := info.ContainerReference{
+ Name: "container",
+ }
+
+ trace := buildTrace(cpuTrace, memTrace, 1*time.Second)
+
+ for _, stats := range trace {
+ driver.AddStats(ref, stats)
+ }
+
+ recentStats, err := driver.RecentStats(ref.Name, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(recentStats) > 0 {
+ t.Errorf("RecentStats() returns %v stats when requests for 0 stats", len(recentStats))
+ }
+}
+
+func StorageDriverTestRetrieveZeroSamples(driver storage.StorageDriver, t *testing.T) {
+ defer driver.Close()
+ N := 100
+ memTrace := make([]uint64, N)
+ cpuTrace := make([]uint64, N)
+ for i := 0; i < N; i++ {
+ memTrace[i] = uint64(i + 1)
+ cpuTrace[i] = uint64(1)
+ }
+
+ ref := info.ContainerReference{
+ Name: "container",
+ }
+
+ trace := buildTrace(cpuTrace, memTrace, 1*time.Second)
+
+ for _, stats := range trace {
+ driver.AddStats(ref, stats)
+ }
+
+ samples, err := driver.Samples(ref.Name, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(samples) > 0 {
+ t.Errorf("RecentStats() returns %v stats when requests for 0 stats", len(samples))
+ }
+}
diff --git a/third_party/src/github.com/google/cadvisor/utils/fs/fs.go b/third_party/src/github.com/google/cadvisor/utils/fs/fs.go
new file mode 100644
index 00000000000..d5999a9b30b
--- /dev/null
+++ b/third_party/src/github.com/google/cadvisor/utils/fs/fs.go
@@ -0,0 +1,44 @@
+// Copyright 2014 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 fs
+
+import (
+ "io"
+ "os"
+)
+
+type osFS struct{}
+
+func (osFS) Open(name string) (File, error) { return os.Open(name) }
+func (osFS) Stat(name string) (os.FileInfo, error) { return os.Stat(name) }
+
+var fs FileSystem = osFS{}
+
+type FileSystem interface {
+ Open(name string) (File, error)
+}
+
+type File interface {
+ io.ReadWriteCloser
+}
+
+// Useful for tests. Not thread safe.
+func ChangeFileSystem(filesystem FileSystem) {
+ fs = filesystem
+}
+
+func Open(name string) (File, error) {
+ return fs.Open(name)
+}
diff --git a/third_party/src/github.com/google/cadvisor/utils/fs/mockfs/fakefile.go b/third_party/src/github.com/google/cadvisor/utils/fs/mockfs/fakefile.go
new file mode 100644
index 00000000000..77a3f48734b
--- /dev/null
+++ b/third_party/src/github.com/google/cadvisor/utils/fs/mockfs/fakefile.go
@@ -0,0 +1,35 @@
+// Copyright 2014 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 mockfs
+
+import "bytes"
+
+type FakeFile struct {
+ bytes.Buffer
+ Name string
+}
+
+func (self *FakeFile) Close() error {
+ return nil
+}
+
+func AddTextFile(mockfs *MockFileSystem, name, content string) *FakeFile {
+ f := &FakeFile{
+ Name: name,
+ Buffer: *bytes.NewBufferString(content),
+ }
+ mockfs.EXPECT().Open(name).Return(f, nil).AnyTimes()
+ return f
+}
diff --git a/third_party/src/github.com/google/cadvisor/utils/fs/mockfs/mockfs.go b/third_party/src/github.com/google/cadvisor/utils/fs/mockfs/mockfs.go
new file mode 100644
index 00000000000..93f08a686e4
--- /dev/null
+++ b/third_party/src/github.com/google/cadvisor/utils/fs/mockfs/mockfs.go
@@ -0,0 +1,55 @@
+// Copyright 2014 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.
+
+// Automatically generated by MockGen. DO NOT EDIT!
+// Source: github.com/google/cadvisor/utils/fs (interfaces: FileSystem)
+
+package mockfs
+
+import (
+ gomock "code.google.com/p/gomock/gomock"
+ fs "github.com/google/cadvisor/utils/fs"
+)
+
+// Mock of FileSystem interface
+type MockFileSystem struct {
+ ctrl *gomock.Controller
+ recorder *_MockFileSystemRecorder
+}
+
+// Recorder for MockFileSystem (not exported)
+type _MockFileSystemRecorder struct {
+ mock *MockFileSystem
+}
+
+func NewMockFileSystem(ctrl *gomock.Controller) *MockFileSystem {
+ mock := &MockFileSystem{ctrl: ctrl}
+ mock.recorder = &_MockFileSystemRecorder{mock}
+ return mock
+}
+
+func (_m *MockFileSystem) EXPECT() *_MockFileSystemRecorder {
+ return _m.recorder
+}
+
+func (_m *MockFileSystem) Open(_param0 string) (fs.File, error) {
+ ret := _m.ctrl.Call(_m, "Open", _param0)
+ ret0, _ := ret[0].(fs.File)
+ ret1, _ := ret[1].(error)
+ return ret0, ret1
+}
+
+func (_mr *_MockFileSystemRecorder) Open(arg0 interface{}) *gomock.Call {
+ return _mr.mock.ctrl.RecordCall(_mr.mock, "Open", arg0)
+}
diff --git a/third_party/src/github.com/google/cadvisor/utils/path.go b/third_party/src/github.com/google/cadvisor/utils/path.go
new file mode 100644
index 00000000000..a7aceee6615
--- /dev/null
+++ b/third_party/src/github.com/google/cadvisor/utils/path.go
@@ -0,0 +1,24 @@
+// Copyright 2014 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 "os"
+
+func FileExists(file string) bool {
+ if _, err := os.Stat(file); err != nil {
+ return false
+ }
+ return true
+}
diff --git a/third_party/src/github.com/google/cadvisor/utils/procfs/doc.go b/third_party/src/github.com/google/cadvisor/utils/procfs/doc.go
new file mode 100644
index 00000000000..763a556c553
--- /dev/null
+++ b/third_party/src/github.com/google/cadvisor/utils/procfs/doc.go
@@ -0,0 +1,17 @@
+// Copyright 2014 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.
+
+// procfs contains several low level functions to read information from /proc
+// filesystem, and also provides some utility functions like JiffiesToDuration.
+package procfs
diff --git a/third_party/src/github.com/google/cadvisor/utils/procfs/jiffy.go b/third_party/src/github.com/google/cadvisor/utils/procfs/jiffy.go
new file mode 100644
index 00000000000..b36772a2525
--- /dev/null
+++ b/third_party/src/github.com/google/cadvisor/utils/procfs/jiffy.go
@@ -0,0 +1,33 @@
+// Copyright 2014 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 procfs
+
+/*
+#include
+*/
+import "C"
+import "time"
+
+var userHz uint64
+
+func init() {
+ userHzLong := C.sysconf(C._SC_CLK_TCK)
+ userHz = uint64(userHzLong)
+}
+
+func JiffiesToDuration(jiffies uint64) time.Duration {
+ d := jiffies * 1000000000 / userHz
+ return time.Duration(d)
+}
diff --git a/third_party/src/github.com/google/cadvisor/utils/procfs/schedstats.go b/third_party/src/github.com/google/cadvisor/utils/procfs/schedstats.go
new file mode 100644
index 00000000000..560b0d43ae5
--- /dev/null
+++ b/third_party/src/github.com/google/cadvisor/utils/procfs/schedstats.go
@@ -0,0 +1,87 @@
+// Copyright 2014 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 procfs
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "strconv"
+
+ "github.com/google/cadvisor/utils/fs"
+)
+
+type ProcessSchedStat struct {
+ // Number of processes
+ NumProcesses int
+
+ // Total time spent on the cpu (Unit: jiffy)
+ Running uint64
+
+ // Total time spent waiting on a runqueue (Unit: jiffy)
+ RunWait uint64
+
+ // # of timeslices run on this cpu (Unit: jiffy)
+ NumTimeSlices uint64
+}
+
+func readUint64List(r io.Reader) ([]uint64, error) {
+ ret := make([]uint64, 0, 4)
+ scanner := bufio.NewScanner(r)
+ scanner.Split(bufio.ScanWords)
+
+ for scanner.Scan() {
+ str := scanner.Text()
+ u, err := strconv.ParseUint(str, 10, 64)
+ if err != nil {
+ return nil, err
+ }
+ ret = append(ret, u)
+ }
+
+ if err := scanner.Err(); err != nil {
+ return nil, err
+ }
+
+ return ret, nil
+}
+
+// Add() read the schedstat of pid, and add stat to the fields
+// in self parameters. This function is useful if one wants to read stats of
+// a group of processes.
+func (self *ProcessSchedStat) Add(pid int) error {
+ if self == nil {
+ return fmt.Errorf("nil stat")
+ }
+
+ path := fmt.Sprintf("/proc/%d/schedstat", pid)
+ f, err := fs.Open(path)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ v, err := readUint64List(f)
+ if err != nil {
+ return err
+ }
+ if len(v) < 3 {
+ return fmt.Errorf("only %v fields read from %v: %v", len(v), path, v)
+ }
+ self.Running += v[0]
+ self.RunWait += v[1]
+ self.NumTimeSlices += v[2]
+ self.NumProcesses++
+ return nil
+}
diff --git a/third_party/src/github.com/google/cadvisor/utils/procfs/schedstats_test.go b/third_party/src/github.com/google/cadvisor/utils/procfs/schedstats_test.go
new file mode 100644
index 00000000000..eae182ef399
--- /dev/null
+++ b/third_party/src/github.com/google/cadvisor/utils/procfs/schedstats_test.go
@@ -0,0 +1,57 @@
+// Copyright 2014 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 procfs
+
+import (
+ "fmt"
+ "reflect"
+ "testing"
+
+ "code.google.com/p/gomock/gomock"
+
+ "github.com/google/cadvisor/utils/fs"
+ "github.com/google/cadvisor/utils/fs/mockfs"
+)
+
+func TestReadProcessSchedStat(t *testing.T) {
+
+ mockCtrl := gomock.NewController(t)
+ defer mockCtrl.Finish()
+
+ mfs := mockfs.NewMockFileSystem(mockCtrl)
+
+ pid := 10
+
+ stat := &ProcessSchedStat{
+ NumProcesses: 1,
+ Running: 100,
+ RunWait: 120,
+ NumTimeSlices: 130,
+ }
+
+ path := fmt.Sprintf("/proc/%v/schedstat", pid)
+ content := fmt.Sprintf("%v %v %v\n", stat.Running, stat.RunWait, stat.NumTimeSlices)
+ mockfs.AddTextFile(mfs, path, content)
+ fs.ChangeFileSystem(mfs)
+
+ receivedStat := &ProcessSchedStat{}
+ err := receivedStat.Add(pid)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !reflect.DeepEqual(receivedStat, stat) {
+ t.Errorf("Received wrong schedstat: %+v", receivedStat)
+ }
+}