Skip to content

Commit 11d2aa0

Browse files
author
Ma Shimiao
committed
cgroup memory: Enchance stats support of memory
Signed-off-by: Ma Shimiao <[email protected]>
1 parent 97f4592 commit 11d2aa0

File tree

5 files changed

+96
-37
lines changed

5 files changed

+96
-37
lines changed

cgroups/fs/memory.go

Lines changed: 50 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"os"
99
"path/filepath"
1010
"strconv"
11+
"strings"
1112

1213
"github.com/docker/libcontainer/cgroups"
1314
"github.com/docker/libcontainer/configs"
@@ -94,24 +95,62 @@ func (s *MemoryGroup) GetStats(path string, stats *cgroups.Stats) error {
9495
}
9596
stats.MemoryStats.Stats[t] = v
9697
}
98+
stats.MemoryStats.Cache = stats.MemoryStats.Stats["cache"]
9799

98-
// Set memory usage and max historical usage.
99-
value, err := getCgroupParamUint(path, "memory.usage_in_bytes")
100+
memoryUsage, err := getMemoryData(path, "")
100101
if err != nil {
101-
return fmt.Errorf("failed to parse memory.usage_in_bytes - %v", err)
102+
return err
102103
}
103-
stats.MemoryStats.Usage = value
104-
stats.MemoryStats.Cache = stats.MemoryStats.Stats["cache"]
105-
value, err = getCgroupParamUint(path, "memory.max_usage_in_bytes")
104+
stats.MemoryStats.Usage = memoryUsage
105+
swapUsage, err := getMemoryData(path, "memsw")
106106
if err != nil {
107-
return fmt.Errorf("failed to parse memory.max_usage_in_bytes - %v", err)
107+
return err
108108
}
109-
stats.MemoryStats.MaxUsage = value
110-
value, err = getCgroupParamUint(path, "memory.failcnt")
109+
stats.MemoryStats.SwapUsage = swapUsage
110+
kernelUsage, err := getMemoryData(path, "kmem")
111111
if err != nil {
112-
return fmt.Errorf("failed to parse memory.failcnt - %v", err)
112+
return err
113113
}
114-
stats.MemoryStats.Failcnt = value
114+
stats.MemoryStats.KernelUsage = kernelUsage
115115

116116
return nil
117117
}
118+
119+
func getMemoryData(path, name string) (cgroups.MemoryData, error) {
120+
memoryData := cgroups.MemoryData{}
121+
122+
moduleName := "memory"
123+
if name != "" {
124+
moduleName = strings.Join([]string{"memory", name}, ".")
125+
}
126+
usage := strings.Join([]string{moduleName, "usage_in_bytes"}, ".")
127+
maxUsage := strings.Join([]string{moduleName, "max_usage_in_bytes"}, ".")
128+
failcnt := strings.Join([]string{moduleName, "failcnt"}, ".")
129+
130+
value, err := getCgroupParamUint(path, usage)
131+
if err != nil {
132+
if moduleName != "memory" && os.IsNotExist(err) {
133+
return cgroups.MemoryData{}, nil
134+
}
135+
return cgroups.MemoryData{}, fmt.Errorf("failed to parse %s - %v", usage, err)
136+
}
137+
memoryData.Usage = value
138+
value, err = getCgroupParamUint(path, maxUsage)
139+
if err != nil {
140+
if moduleName != "memory" && os.IsNotExist(err) {
141+
return cgroups.MemoryData{}, nil
142+
}
143+
return cgroups.MemoryData{}, fmt.Errorf("failed to parse %s - %v", maxUsage, err)
144+
}
145+
memoryData.MaxUsage = value
146+
value, err = getCgroupParamUint(path, failcnt)
147+
if err != nil {
148+
if moduleName != "memory" && os.IsNotExist(err) {
149+
return cgroups.MemoryData{}, nil
150+
}
151+
return cgroups.MemoryData{}, fmt.Errorf("failed to parse %s - %v", failcnt, err)
152+
}
153+
memoryData.Failcnt = value
154+
155+
return memoryData, nil
156+
}

cgroups/fs/memory_test.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -146,10 +146,16 @@ func TestMemoryStats(t *testing.T) {
146146
helper := NewCgroupTestUtil("memory", t)
147147
defer helper.cleanup()
148148
helper.writeFileContents(map[string]string{
149-
"memory.stat": memoryStatContents,
150-
"memory.usage_in_bytes": memoryUsageContents,
151-
"memory.max_usage_in_bytes": memoryMaxUsageContents,
152-
"memory.failcnt": memoryFailcnt,
149+
"memory.stat": memoryStatContents,
150+
"memory.usage_in_bytes": memoryUsageContents,
151+
"memory.max_usage_in_bytes": memoryMaxUsageContents,
152+
"memory.failcnt": memoryFailcnt,
153+
"memory.memsw.usage_in_bytes": memoryUsageContents,
154+
"memory.memsw.max_usage_in_bytes": memoryMaxUsageContents,
155+
"memory.memsw.failcnt": memoryFailcnt,
156+
"memory.kmem.usage_in_bytes": memoryUsageContents,
157+
"memory.kmem.max_usage_in_bytes": memoryMaxUsageContents,
158+
"memory.kmem.failcnt": memoryFailcnt,
153159
})
154160

155161
memory := &MemoryGroup{}
@@ -158,7 +164,7 @@ func TestMemoryStats(t *testing.T) {
158164
if err != nil {
159165
t.Fatal(err)
160166
}
161-
expectedStats := cgroups.MemoryStats{Usage: 2048, Cache: 512, MaxUsage: 4096, Failcnt: 100, Stats: map[string]uint64{"cache": 512, "rss": 1024}}
167+
expectedStats := cgroups.MemoryStats{Cache: 512, Usage: cgroups.MemoryData{Usage: 2048, MaxUsage: 4096, Failcnt: 100}, SwapUsage: cgroups.MemoryData{Usage: 2048, MaxUsage: 4096, Failcnt: 100}, KernelUsage: cgroups.MemoryData{Usage: 2048, MaxUsage: 4096, Failcnt: 100}, Stats: map[string]uint64{"cache": 512, "rss": 1024}}
162168
expectMemoryStatEquals(t, expectedStats, actualStats.MemoryStats)
163169
}
164170

cgroups/fs/stats_util_test.go

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -73,14 +73,10 @@ func expectThrottlingDataEquals(t *testing.T, expected, actual cgroups.Throttlin
7373
}
7474

7575
func expectMemoryStatEquals(t *testing.T, expected, actual cgroups.MemoryStats) {
76-
if expected.Usage != actual.Usage {
77-
logrus.Printf("Expected memory usage %d but found %d\n", expected.Usage, actual.Usage)
78-
t.Fail()
79-
}
80-
if expected.MaxUsage != actual.MaxUsage {
81-
logrus.Printf("Expected memory max usage %d but found %d\n", expected.MaxUsage, actual.MaxUsage)
82-
t.Fail()
83-
}
76+
expectMemoryDataEquals(t, expected.Usage, actual.Usage)
77+
expectMemoryDataEquals(t, expected.SwapUsage, actual.SwapUsage)
78+
expectMemoryDataEquals(t, expected.KernelUsage, actual.KernelUsage)
79+
8480
for key, expValue := range expected.Stats {
8581
actValue, ok := actual.Stats[key]
8682
if !ok {
@@ -92,6 +88,17 @@ func expectMemoryStatEquals(t *testing.T, expected, actual cgroups.MemoryStats)
9288
t.Fail()
9389
}
9490
}
91+
}
92+
93+
func expectMemoryDataEquals(t *testing.T, expected, actual cgroups.MemoryData) {
94+
if expected.Usage != actual.Usage {
95+
logrus.Printf("Expected memory usage %d but found %d\n", expected.Usage, actual.Usage)
96+
t.Fail()
97+
}
98+
if expected.MaxUsage != actual.MaxUsage {
99+
logrus.Printf("Expected memory max usage %d but found %d\n", expected.MaxUsage, actual.MaxUsage)
100+
t.Fail()
101+
}
95102
if expected.Failcnt != actual.Failcnt {
96103
logrus.Printf("Expected memory failcnt %d but found %d\n", expected.Failcnt, actual.Failcnt)
97104
t.Fail()

cgroups/stats.go

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -32,18 +32,21 @@ type CpuStats struct {
3232
ThrottlingData ThrottlingData `json:"throttling_data,omitempty"`
3333
}
3434

35+
type MemoryData struct {
36+
Usage uint64 `json:"usage,omitempty"`
37+
MaxUsage uint64 `json:"max_usage,omitempty"`
38+
Failcnt uint64 `json:"failcnt"`
39+
}
3540
type MemoryStats struct {
36-
// current res_counter usage for memory
37-
Usage uint64 `json:"usage,omitempty"`
3841
// memory used for cache
3942
Cache uint64 `json:"cache,omitempty"`
40-
// maximum usage ever recorded.
41-
MaxUsage uint64 `json:"max_usage,omitempty"`
42-
// TODO(vishh): Export these as stronger types.
43-
// all the stats exported via memory.stat.
44-
Stats map[string]uint64 `json:"stats,omitempty"`
45-
// number of times memory usage hits limits.
46-
Failcnt uint64 `json:"failcnt"`
43+
// usage of memory
44+
Usage MemoryData `json:"usage,omitempty"`
45+
// usage of memory + swap
46+
SwapUsage MemoryData `json:"swap_usage,omitempty"`
47+
// usafe of kernel memory
48+
KernelUsage MemoryData `json:"kernel_usage,omitempty"`
49+
Stats map[string]uint64 `json:"stats,omitempty"`
4750
}
4851

4952
type BlkioStatEntry struct {

container_linux_test.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,9 @@ func TestGetContainerStats(t *testing.T) {
106106
pids: []int{1, 2, 3},
107107
stats: &cgroups.Stats{
108108
MemoryStats: cgroups.MemoryStats{
109-
Usage: 1024,
109+
Usage: cgroups.MemoryData{
110+
Usage: 1024,
111+
},
110112
},
111113
},
112114
},
@@ -118,8 +120,8 @@ func TestGetContainerStats(t *testing.T) {
118120
if stats.CgroupStats == nil {
119121
t.Fatal("cgroup stats are nil")
120122
}
121-
if stats.CgroupStats.MemoryStats.Usage != 1024 {
122-
t.Fatalf("expected memory usage 1024 but recevied %d", stats.CgroupStats.MemoryStats.Usage)
123+
if stats.CgroupStats.MemoryStats.Usage.Usage != 1024 {
124+
t.Fatalf("expected memory usage 1024 but recevied %d", stats.CgroupStats.MemoryStats.Usage.Usage)
123125
}
124126
}
125127

@@ -149,7 +151,9 @@ func TestGetContainerState(t *testing.T) {
149151
pids: []int{1, 2, 3},
150152
stats: &cgroups.Stats{
151153
MemoryStats: cgroups.MemoryStats{
152-
Usage: 1024,
154+
Usage: cgroups.MemoryData{
155+
Usage: 1024,
156+
},
153157
},
154158
},
155159
paths: map[string]string{

0 commit comments

Comments
 (0)