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:
parent
2616e87cad
commit
59c33dfe0b
4 changed files with 39 additions and 20 deletions
|
@ -20,6 +20,8 @@ var (
|
|||
clockTicks = uint64(system.GetClockTicks())
|
||||
)
|
||||
|
||||
const nanosecondsInSecond = 1000000000
|
||||
|
||||
type cpuacctGroup struct {
|
||||
}
|
||||
|
||||
|
@ -37,13 +39,13 @@ func (s *cpuacctGroup) Remove(d *data) error {
|
|||
|
||||
func (s *cpuacctGroup) GetStats(d *data, stats *cgroups.Stats) error {
|
||||
var (
|
||||
startCpu, lastCpu, startSystem, lastSystem, startUsage, lastUsage uint64
|
||||
percentage uint64
|
||||
startCpu, lastCpu, startSystem, lastSystem, startUsage, lastUsage, kernelModeUsage, userModeUsage, percentage uint64
|
||||
)
|
||||
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
|
||||
}
|
||||
startCpu = kernelModeUsage + userModeUsage
|
||||
if startSystem, err = s.getSystemCpuUsage(d); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -53,9 +55,10 @@ func (s *cpuacctGroup) GetStats(d *data, stats *cgroups.Stats) error {
|
|||
}
|
||||
// sample for 100ms
|
||||
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
|
||||
}
|
||||
lastCpu = kernelModeUsage + userModeUsage
|
||||
if lastSystem, err = s.getSystemCpuUsage(d); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -82,6 +85,8 @@ func (s *cpuacctGroup) GetStats(d *data, stats *cgroups.Stats) error {
|
|||
return err
|
||||
}
|
||||
stats.CpuStats.CpuUsage.PercpuUsage = percpuUsage
|
||||
stats.CpuStats.CpuUsage.UsageInKernelmode = (kernelModeUsage * nanosecondsInSecond) / clockTicks
|
||||
stats.CpuStats.CpuUsage.UsageInUsermode = (userModeUsage * nanosecondsInSecond) / clockTicks
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -119,24 +124,25 @@ func (s *cpuacctGroup) getSystemCpuUsage(d *data) (uint64, error) {
|
|||
return 0, fmt.Errorf("invalid stat format")
|
||||
}
|
||||
|
||||
func (s *cpuacctGroup) getCpuUsage(d *data, path string) (uint64, error) {
|
||||
cpuTotal := uint64(0)
|
||||
f, err := os.Open(filepath.Join(path, "cpuacct.stat"))
|
||||
func (s *cpuacctGroup) getCpuUsage(d *data, path string) (uint64, uint64, error) {
|
||||
kernelModeUsage := uint64(0)
|
||||
userModeUsage := uint64(0)
|
||||
data, err := ioutil.ReadFile(filepath.Join(path, "cpuacct.stat"))
|
||||
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)
|
||||
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
|
||||
return kernelModeUsage, userModeUsage, nil
|
||||
}
|
||||
|
||||
func (s *cpuacctGroup) getPercpuUsage(path string) ([]uint64, error) {
|
||||
|
|
|
@ -84,6 +84,11 @@ func (s *memoryGroup) GetStats(d *data, stats *cgroups.Stats) error {
|
|||
return err
|
||||
}
|
||||
stats.MemoryStats.MaxUsage = value
|
||||
value, err = getCgroupParamInt(path, "memory.failcnt")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
stats.MemoryStats.Failcnt = value
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ const (
|
|||
rss 1024`
|
||||
memoryUsageContents = "2048\n"
|
||||
memoryMaxUsageContents = "4096\n"
|
||||
memoryFailcnt = "100\n"
|
||||
)
|
||||
|
||||
func TestMemoryStats(t *testing.T) {
|
||||
|
@ -20,6 +21,7 @@ func TestMemoryStats(t *testing.T) {
|
|||
"memory.stat": memoryStatContents,
|
||||
"memory.usage_in_bytes": memoryUsageContents,
|
||||
"memory.max_usage_in_bytes": memoryMaxUsageContents,
|
||||
"memory.failcnt": memoryFailcnt,
|
||||
})
|
||||
|
||||
memory := &memoryGroup{}
|
||||
|
@ -27,7 +29,7 @@ func TestMemoryStats(t *testing.T) {
|
|||
if err != nil {
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,10 @@ type CpuUsage struct {
|
|||
// nanoseconds of cpu time consumed over the last 100 ms.
|
||||
CurrentUsage uint64 `json:"current_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 {
|
||||
|
@ -30,6 +34,8 @@ type MemoryStats struct {
|
|||
// TODO(vishh): Export these as stronger types.
|
||||
// all the stats exported via memory.stat.
|
||||
Stats map[string]uint64 `json:"stats,omitempty"`
|
||||
// number of times memory usage hits limits.
|
||||
Failcnt uint64 `json:"failcnt"`
|
||||
}
|
||||
|
||||
type BlkioStatEntry struct {
|
||||
|
|
Loading…
Reference in a new issue