Add stats for memory allocation failure count and instantaneous cpu usage in the usermode and kernelmode.

Docker-DCO-1.1-Signed-off-by: Vishnu Kannan <vishnuk@google.com> (github: vishh)
This commit is contained in:
Vishnu Kannan 2014-06-04 06:41:03 +00:00
parent 2616e87cad
commit 59c33dfe0b
4 changed files with 39 additions and 20 deletions

View file

@ -20,6 +20,8 @@ var (
clockTicks = uint64(system.GetClockTicks()) clockTicks = uint64(system.GetClockTicks())
) )
const nanosecondsInSecond = 1000000000
type cpuacctGroup struct { type cpuacctGroup struct {
} }
@ -37,13 +39,13 @@ func (s *cpuacctGroup) Remove(d *data) error {
func (s *cpuacctGroup) GetStats(d *data, stats *cgroups.Stats) error { func (s *cpuacctGroup) GetStats(d *data, stats *cgroups.Stats) error {
var ( var (
startCpu, lastCpu, startSystem, lastSystem, startUsage, lastUsage uint64 startCpu, lastCpu, startSystem, lastSystem, startUsage, lastUsage, kernelModeUsage, userModeUsage, percentage uint64
percentage uint64
) )
path, err := d.path("cpuacct") path, err := d.path("cpuacct")
if startCpu, err = s.getCpuUsage(d, path); err != nil { if kernelModeUsage, userModeUsage, err = s.getCpuUsage(d, path); err != nil {
return err return err
} }
startCpu = kernelModeUsage + userModeUsage
if startSystem, err = s.getSystemCpuUsage(d); err != nil { if startSystem, err = s.getSystemCpuUsage(d); err != nil {
return err return err
} }
@ -53,9 +55,10 @@ func (s *cpuacctGroup) GetStats(d *data, stats *cgroups.Stats) error {
} }
// sample for 100ms // sample for 100ms
time.Sleep(100 * time.Millisecond) time.Sleep(100 * time.Millisecond)
if lastCpu, err = s.getCpuUsage(d, path); err != nil { if kernelModeUsage, userModeUsage, err = s.getCpuUsage(d, path); err != nil {
return err return err
} }
lastCpu = kernelModeUsage + userModeUsage
if lastSystem, err = s.getSystemCpuUsage(d); err != nil { if lastSystem, err = s.getSystemCpuUsage(d); err != nil {
return err return err
} }
@ -82,6 +85,8 @@ func (s *cpuacctGroup) GetStats(d *data, stats *cgroups.Stats) error {
return err return err
} }
stats.CpuStats.CpuUsage.PercpuUsage = percpuUsage stats.CpuStats.CpuUsage.PercpuUsage = percpuUsage
stats.CpuStats.CpuUsage.UsageInKernelmode = (kernelModeUsage * nanosecondsInSecond) / clockTicks
stats.CpuStats.CpuUsage.UsageInUsermode = (userModeUsage * nanosecondsInSecond) / clockTicks
return nil return nil
} }
@ -119,24 +124,25 @@ func (s *cpuacctGroup) getSystemCpuUsage(d *data) (uint64, error) {
return 0, fmt.Errorf("invalid stat format") return 0, fmt.Errorf("invalid stat format")
} }
func (s *cpuacctGroup) getCpuUsage(d *data, path string) (uint64, error) { func (s *cpuacctGroup) getCpuUsage(d *data, path string) (uint64, uint64, error) {
cpuTotal := uint64(0) kernelModeUsage := uint64(0)
f, err := os.Open(filepath.Join(path, "cpuacct.stat")) userModeUsage := uint64(0)
data, err := ioutil.ReadFile(filepath.Join(path, "cpuacct.stat"))
if err != nil { if err != nil {
return 0, err return 0, 0, err
}
fields := strings.Fields(string(data))
if len(fields) != 4 {
return 0, 0, fmt.Errorf("Failure - %s is expected to have 4 fields", filepath.Join(path, "cpuacct.stat"))
}
if userModeUsage, err = strconv.ParseUint(fields[1], 10, 64); err != nil {
return 0, 0, err
}
if kernelModeUsage, err = strconv.ParseUint(fields[3], 10, 64); err != nil {
return 0, 0, err
} }
defer f.Close()
sc := bufio.NewScanner(f) return kernelModeUsage, userModeUsage, nil
for sc.Scan() {
_, v, err := getCgroupParamKeyValue(sc.Text())
if err != nil {
return 0, err
}
// set the raw data in map
cpuTotal += v
}
return cpuTotal, nil
} }
func (s *cpuacctGroup) getPercpuUsage(path string) ([]uint64, error) { func (s *cpuacctGroup) getPercpuUsage(path string) ([]uint64, error) {

View file

@ -84,6 +84,11 @@ func (s *memoryGroup) GetStats(d *data, stats *cgroups.Stats) error {
return err return err
} }
stats.MemoryStats.MaxUsage = value stats.MemoryStats.MaxUsage = value
value, err = getCgroupParamInt(path, "memory.failcnt")
if err != nil {
return err
}
stats.MemoryStats.Failcnt = value
return nil return nil
} }

View file

@ -11,6 +11,7 @@ const (
rss 1024` rss 1024`
memoryUsageContents = "2048\n" memoryUsageContents = "2048\n"
memoryMaxUsageContents = "4096\n" memoryMaxUsageContents = "4096\n"
memoryFailcnt = "100\n"
) )
func TestMemoryStats(t *testing.T) { func TestMemoryStats(t *testing.T) {
@ -20,6 +21,7 @@ func TestMemoryStats(t *testing.T) {
"memory.stat": memoryStatContents, "memory.stat": memoryStatContents,
"memory.usage_in_bytes": memoryUsageContents, "memory.usage_in_bytes": memoryUsageContents,
"memory.max_usage_in_bytes": memoryMaxUsageContents, "memory.max_usage_in_bytes": memoryMaxUsageContents,
"memory.failcnt": memoryFailcnt,
}) })
memory := &memoryGroup{} memory := &memoryGroup{}
@ -27,7 +29,7 @@ func TestMemoryStats(t *testing.T) {
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
expectedStats := cgroups.MemoryStats{Usage: 2048, MaxUsage: 4096, Stats: map[string]uint64{"cache": 512, "rss": 1024}} expectedStats := cgroups.MemoryStats{Usage: 2048, MaxUsage: 4096, Failcnt: 100, Stats: map[string]uint64{"cache": 512, "rss": 1024}}
expectMemoryStatEquals(t, expectedStats, actualStats.MemoryStats) expectMemoryStatEquals(t, expectedStats, actualStats.MemoryStats)
} }

View file

@ -15,6 +15,10 @@ type CpuUsage struct {
// nanoseconds of cpu time consumed over the last 100 ms. // nanoseconds of cpu time consumed over the last 100 ms.
CurrentUsage uint64 `json:"current_usage,omitempty"` CurrentUsage uint64 `json:"current_usage,omitempty"`
PercpuUsage []uint64 `json:"percpu_usage,omitempty"` PercpuUsage []uint64 `json:"percpu_usage,omitempty"`
// Time spent by tasks of the cgroup in kernel mode. Units: nanoseconds.
UsageInKernelmode uint64 `json:"usage_in_kernelmode"`
// Time spent by tasks of the cgroup in user mode. Units: nanoseconds.
UsageInUsermode uint64 `json:"usage_in_usermode"`
} }
type CpuStats struct { type CpuStats struct {
@ -30,6 +34,8 @@ type MemoryStats struct {
// TODO(vishh): Export these as stronger types. // TODO(vishh): Export these as stronger types.
// all the stats exported via memory.stat. // all the stats exported via memory.stat.
Stats map[string]uint64 `json:"stats,omitempty"` Stats map[string]uint64 `json:"stats,omitempty"`
// number of times memory usage hits limits.
Failcnt uint64 `json:"failcnt"`
} }
type BlkioStatEntry struct { type BlkioStatEntry struct {