Skip to content

Commit d74f62e

Browse files
committed
Add reading of information from cpuacct.usage_all
Remove logrus logs from tests Signed-off-by: Katarzyna Kujawa <[email protected]>
1 parent 96596cb commit d74f62e

File tree

6 files changed

+180
-41
lines changed

6 files changed

+180
-41
lines changed

events.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ func convertLibcontainerStats(ls *libcontainer.Stats) *types.Stats {
125125
s.CPU.Usage.User = cg.CpuStats.CpuUsage.UsageInUsermode
126126
s.CPU.Usage.Total = cg.CpuStats.CpuUsage.TotalUsage
127127
s.CPU.Usage.Percpu = cg.CpuStats.CpuUsage.PercpuUsage
128+
s.CPU.Usage.PercpuKernel = cg.CpuStats.CpuUsage.PercpuUsageInKernelmode
129+
s.CPU.Usage.PercpuUser = cg.CpuStats.CpuUsage.PercpuUsageInUsermode
128130
s.CPU.Throttling.Periods = cg.CpuStats.ThrottlingData.Periods
129131
s.CPU.Throttling.ThrottledPeriods = cg.CpuStats.ThrottlingData.ThrottledPeriods
130132
s.CPU.Throttling.ThrottledTime = cg.CpuStats.ThrottlingData.ThrottledTime

libcontainer/cgroups/fs/cpuacct.go

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33
package fs
44

55
import (
6+
"bufio"
67
"fmt"
78
"io/ioutil"
9+
"os"
810
"path/filepath"
911
"strconv"
1012
"strings"
@@ -16,8 +18,14 @@ import (
1618
)
1719

1820
const (
19-
cgroupCpuacctStat = "cpuacct.stat"
21+
cgroupCpuacctStat = "cpuacct.stat"
22+
cgroupCpuacctUsageAll = "cpuacct.usage_all"
23+
2024
nanosecondsInSecond = 1000000000
25+
26+
userModeColumn = 1
27+
kernelModeColumn = 2
28+
cuacctUsageAllColumnsNumber = 3
2129
)
2230

2331
var clockTicks = uint64(system.GetClockTicks())
@@ -62,8 +70,15 @@ func (s *CpuacctGroup) GetStats(path string, stats *cgroups.Stats) error {
6270
return err
6371
}
6472

73+
PercpuUsageInKernelmode, PercpuUsageInUsermode, err := getPercpuUsageInModes(path)
74+
if err != nil {
75+
return err
76+
}
77+
6578
stats.CpuStats.CpuUsage.TotalUsage = totalUsage
6679
stats.CpuStats.CpuUsage.PercpuUsage = percpuUsage
80+
stats.CpuStats.CpuUsage.PercpuUsageInKernelmode = PercpuUsageInKernelmode
81+
stats.CpuStats.CpuUsage.PercpuUsageInUsermode = PercpuUsageInUsermode
6782
stats.CpuStats.CpuUsage.UsageInUsermode = userModeUsage
6883
stats.CpuStats.CpuUsage.UsageInKernelmode = kernelModeUsage
6984
return nil
@@ -120,3 +135,42 @@ func getPercpuUsage(path string) ([]uint64, error) {
120135
}
121136
return percpuUsage, nil
122137
}
138+
139+
func getPercpuUsageInModes(path string) ([]uint64, []uint64, error) {
140+
percpuUsageKernelMode := []uint64{}
141+
percpuUsageUserMode := []uint64{}
142+
143+
file, err := os.Open(filepath.Join(path, cgroupCpuacctUsageAll))
144+
if err != nil {
145+
return nil, nil, err
146+
}
147+
defer file.Close()
148+
149+
scanner := bufio.NewScanner(file)
150+
scanner.Scan() //skipping header line
151+
152+
for scanner.Scan() {
153+
lineFields := strings.SplitN(scanner.Text(), " ", cuacctUsageAllColumnsNumber)
154+
if len(lineFields) != cuacctUsageAllColumnsNumber {
155+
continue
156+
}
157+
158+
usageInKernelMode, err := strconv.ParseUint(lineFields[kernelModeColumn], 10, 64)
159+
if err != nil {
160+
return nil, nil, fmt.Errorf("Unable to convert CPU usage in kernel mode to uint64: %s", err)
161+
}
162+
percpuUsageKernelMode = append(percpuUsageKernelMode, usageInKernelMode)
163+
164+
usageInUserMode, err := strconv.ParseUint(lineFields[userModeColumn], 10, 64)
165+
if err != nil {
166+
return nil, nil, fmt.Errorf("Unable to convert CPU usage in user mode to uint64: %s", err)
167+
}
168+
percpuUsageUserMode = append(percpuUsageUserMode, usageInUserMode)
169+
}
170+
171+
if err := scanner.Err(); err != nil {
172+
return nil, nil, fmt.Errorf("Problem in reading %s line by line, %s", cgroupCpuacctUsageAll, err)
173+
}
174+
175+
return percpuUsageKernelMode, percpuUsageUserMode, nil
176+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// +build linux
2+
3+
package fs
4+
5+
import (
6+
"testing"
7+
8+
"github.com/opencontainers/runc/libcontainer/cgroups"
9+
)
10+
11+
const (
12+
cpuAcctUsageContents = "12262454190222160"
13+
cpuAcctUsagePerCPUContents = "1564936537989058 1583937096487821 1604195415465681 1596445226820187 1481069084155629 1478735613864327 1477610593414743 1476362015778086"
14+
cpuAcctStatContents = "user 452278264\nsystem 291429664"
15+
cpuAcctUsageAll = `cpu user system
16+
0 962250696038415 637727786389114
17+
1 981956408513304 638197595421064
18+
2 1002658817529022 638956774598358
19+
3 994937703492523 637985531181620
20+
4 874843781648690 638837766495476
21+
5 872544369885276 638763309884944
22+
6 870104915696359 640081778921247
23+
7 870202363887496 638716766259495
24+
`
25+
)
26+
27+
func TestCpuacctStats(t *testing.T) {
28+
helper := NewCgroupTestUtil("cpuacct.", t)
29+
defer helper.cleanup()
30+
helper.writeFileContents(map[string]string{
31+
"cpuacct.usage": cpuAcctUsageContents,
32+
"cpuacct.usage_percpu": cpuAcctUsagePerCPUContents,
33+
"cpuacct.stat": cpuAcctStatContents,
34+
"cpuacct.usage_all": cpuAcctUsageAll,
35+
})
36+
37+
cpuacct := &CpuacctGroup{}
38+
actualStats := *cgroups.NewStats()
39+
err := cpuacct.GetStats(helper.CgroupPath, &actualStats)
40+
if err != nil {
41+
t.Fatal(err)
42+
}
43+
44+
expectedStats := cgroups.CpuUsage{
45+
TotalUsage: uint64(12262454190222160),
46+
PercpuUsage: []uint64{1564936537989058, 1583937096487821, 1604195415465681, 1596445226820187,
47+
1481069084155629, 1478735613864327, 1477610593414743, 1476362015778086},
48+
PercpuUsageInKernelmode: []uint64{637727786389114, 638197595421064, 638956774598358, 637985531181620,
49+
638837766495476, 638763309884944, 640081778921247, 638716766259495},
50+
PercpuUsageInUsermode: []uint64{962250696038415, 981956408513304, 1002658817529022, 994937703492523,
51+
874843781648690, 872544369885276, 870104915696359, 870202363887496},
52+
UsageInKernelmode: (uint64(291429664) * nanosecondsInSecond) / clockTicks,
53+
UsageInUsermode: (uint64(452278264) * nanosecondsInSecond) / clockTicks,
54+
}
55+
expectCPUUsageEqual(t, expectedStats, actualStats.CpuStats.CpuUsage)
56+
}

libcontainer/cgroups/fs/stats_util_test.go

Lines changed: 55 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ import (
77
"testing"
88

99
"github.com/opencontainers/runc/libcontainer/cgroups"
10-
11-
"github.com/sirupsen/logrus"
1210
)
1311

1412
func blkioStatEntryEquals(expected, actual []cgroups.BlkioStatEntry) error {
@@ -26,57 +24,47 @@ func blkioStatEntryEquals(expected, actual []cgroups.BlkioStatEntry) error {
2624

2725
func expectBlkioStatsEquals(t *testing.T, expected, actual cgroups.BlkioStats) {
2826
if err := blkioStatEntryEquals(expected.IoServiceBytesRecursive, actual.IoServiceBytesRecursive); err != nil {
29-
logrus.Printf("blkio IoServiceBytesRecursive do not match - %s\n", err)
30-
t.Fail()
27+
t.Errorf("blkio IoServiceBytesRecursive do not match - %s\n", err)
3128
}
3229

3330
if err := blkioStatEntryEquals(expected.IoServicedRecursive, actual.IoServicedRecursive); err != nil {
34-
logrus.Printf("blkio IoServicedRecursive do not match - %s\n", err)
35-
t.Fail()
31+
t.Errorf("blkio IoServicedRecursive do not match - %s\n", err)
3632
}
3733

3834
if err := blkioStatEntryEquals(expected.IoQueuedRecursive, actual.IoQueuedRecursive); err != nil {
39-
logrus.Printf("blkio IoQueuedRecursive do not match - %s\n", err)
40-
t.Fail()
35+
t.Errorf("blkio IoQueuedRecursive do not match - %s\n", err)
4136
}
4237

4338
if err := blkioStatEntryEquals(expected.SectorsRecursive, actual.SectorsRecursive); err != nil {
44-
logrus.Printf("blkio SectorsRecursive do not match - %s\n", err)
45-
t.Fail()
39+
t.Errorf("blkio SectorsRecursive do not match - %s\n", err)
4640
}
4741

4842
if err := blkioStatEntryEquals(expected.IoServiceTimeRecursive, actual.IoServiceTimeRecursive); err != nil {
49-
logrus.Printf("blkio IoServiceTimeRecursive do not match - %s\n", err)
50-
t.Fail()
43+
t.Errorf("blkio IoServiceTimeRecursive do not match - %s\n", err)
5144
}
5245

5346
if err := blkioStatEntryEquals(expected.IoWaitTimeRecursive, actual.IoWaitTimeRecursive); err != nil {
54-
logrus.Printf("blkio IoWaitTimeRecursive do not match - %s\n", err)
55-
t.Fail()
47+
t.Errorf("blkio IoWaitTimeRecursive do not match - %s\n", err)
5648
}
5749

5850
if err := blkioStatEntryEquals(expected.IoMergedRecursive, actual.IoMergedRecursive); err != nil {
59-
logrus.Printf("blkio IoMergedRecursive do not match - %v vs %v\n", expected.IoMergedRecursive, actual.IoMergedRecursive)
60-
t.Fail()
51+
t.Errorf("blkio IoMergedRecursive do not match - %v vs %v\n", expected.IoMergedRecursive, actual.IoMergedRecursive)
6152
}
6253

6354
if err := blkioStatEntryEquals(expected.IoTimeRecursive, actual.IoTimeRecursive); err != nil {
64-
logrus.Printf("blkio IoTimeRecursive do not match - %s\n", err)
65-
t.Fail()
55+
t.Errorf("blkio IoTimeRecursive do not match - %s\n", err)
6656
}
6757
}
6858

6959
func expectThrottlingDataEquals(t *testing.T, expected, actual cgroups.ThrottlingData) {
7060
if expected != actual {
71-
logrus.Printf("Expected throttling data %v but found %v\n", expected, actual)
72-
t.Fail()
61+
t.Errorf("Expected throttling data %v but found %v\n", expected, actual)
7362
}
7463
}
7564

7665
func expectHugetlbStatEquals(t *testing.T, expected, actual cgroups.HugetlbStats) {
7766
if expected != actual {
78-
logrus.Printf("Expected hugetlb stats %v but found %v\n", expected, actual)
79-
t.Fail()
67+
t.Errorf("Expected hugetlb stats %v but found %v\n", expected, actual)
8068
}
8169
}
8270

@@ -86,38 +74,69 @@ func expectMemoryStatEquals(t *testing.T, expected, actual cgroups.MemoryStats)
8674
expectMemoryDataEquals(t, expected.KernelUsage, actual.KernelUsage)
8775

8876
if expected.UseHierarchy != actual.UseHierarchy {
89-
logrus.Printf("Expected memory use hierarchy %v, but found %v\n", expected.UseHierarchy, actual.UseHierarchy)
90-
t.Fail()
77+
t.Errorf("Expected memory use hierarchy %v, but found %v\n", expected.UseHierarchy, actual.UseHierarchy)
9178
}
9279

9380
for key, expValue := range expected.Stats {
9481
actValue, ok := actual.Stats[key]
9582
if !ok {
96-
logrus.Printf("Expected memory stat key %s not found\n", key)
97-
t.Fail()
83+
t.Errorf("Expected memory stat key %s not found\n", key)
9884
}
9985
if expValue != actValue {
100-
logrus.Printf("Expected memory stat value %d but found %d\n", expValue, actValue)
101-
t.Fail()
86+
t.Errorf("Expected memory stat value %d but found %d\n", expValue, actValue)
10287
}
10388
}
10489
}
10590

10691
func expectMemoryDataEquals(t *testing.T, expected, actual cgroups.MemoryData) {
10792
if expected.Usage != actual.Usage {
108-
logrus.Printf("Expected memory usage %d but found %d\n", expected.Usage, actual.Usage)
109-
t.Fail()
93+
t.Errorf("Expected memory usage %d but found %d\n", expected.Usage, actual.Usage)
11094
}
11195
if expected.MaxUsage != actual.MaxUsage {
112-
logrus.Printf("Expected memory max usage %d but found %d\n", expected.MaxUsage, actual.MaxUsage)
113-
t.Fail()
96+
t.Errorf("Expected memory max usage %d but found %d\n", expected.MaxUsage, actual.MaxUsage)
11497
}
11598
if expected.Failcnt != actual.Failcnt {
116-
logrus.Printf("Expected memory failcnt %d but found %d\n", expected.Failcnt, actual.Failcnt)
117-
t.Fail()
99+
t.Errorf("Expected memory failcnt %d but found %d\n", expected.Failcnt, actual.Failcnt)
118100
}
119101
if expected.Limit != actual.Limit {
120-
logrus.Printf("Expected memory limit %d but found %d\n", expected.Limit, actual.Limit)
121-
t.Fail()
102+
t.Errorf("Expected memory limit %d but found %d\n", expected.Limit, actual.Limit)
103+
}
104+
}
105+
106+
func expectCPUUsageEqual(t *testing.T, expected, actual cgroups.CpuUsage) {
107+
if expected.TotalUsage != actual.TotalUsage {
108+
t.Errorf("Expected CPU total usage %d but found %d\n",
109+
expected.TotalUsage, actual.TotalUsage)
110+
}
111+
112+
for cpuID, actualCPUUsage := range actual.PercpuUsage {
113+
if expected.PercpuUsage[cpuID] != actualCPUUsage {
114+
t.Errorf("Expected CPU%d usage %d but found %d\n",
115+
cpuID, expected.PercpuUsage[cpuID], actualCPUUsage)
116+
}
117+
}
118+
119+
for cpuID, actualKernelModeUsage := range actual.PercpuUsageInKernelmode {
120+
if expected.PercpuUsageInKernelmode[cpuID] != actualKernelModeUsage {
121+
t.Errorf("Expected CPU%d usage in kernel mode %d but found %d\n",
122+
cpuID, expected.PercpuUsageInKernelmode[cpuID], actualKernelModeUsage)
123+
}
124+
}
125+
126+
for cpuID, actualUserModeUsage := range actual.PercpuUsageInUsermode {
127+
if expected.PercpuUsageInUsermode[cpuID] != actualUserModeUsage {
128+
t.Errorf("Expected CPU%d usage in user mode %d but found %d\n",
129+
cpuID, expected.PercpuUsageInUsermode[cpuID], actualUserModeUsage)
130+
}
131+
}
132+
133+
if expected.UsageInKernelmode != actual.UsageInKernelmode {
134+
t.Errorf("Expected CPU usage in kernel mode %d but found %d\n",
135+
expected.UsageInKernelmode, actual.UsageInKernelmode)
136+
}
137+
138+
if expected.UsageInUsermode != actual.UsageInUsermode {
139+
t.Errorf("Expected CPU usage in user mode %d but found %d\n",
140+
expected.UsageInUsermode, actual.UsageInUsermode)
122141
}
123142
}

libcontainer/cgroups/stats.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ type CpuUsage struct {
2020
// Total CPU time consumed per core.
2121
// Units: nanoseconds.
2222
PercpuUsage []uint64 `json:"percpu_usage,omitempty"`
23+
// CPU time consumed per core in kernel mode
24+
// Units: nanoseconds.
25+
PercpuUsageInKernelmode []uint64 `json:"percpu_usage_in_kernelmode"`
26+
// CPU time consumed per core in user mode
27+
// Units: nanoseconds.
28+
PercpuUsageInUsermode []uint64 `json:"percpu_usage_in_usermode"`
2329
// Time spent by tasks of the cgroup in kernel mode.
2430
// Units: nanoseconds.
2531
UsageInKernelmode uint64 `json:"usage_in_kernelmode"`

types/events.go

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,12 @@ type Throttling struct {
5555

5656
type CpuUsage struct {
5757
// Units: nanoseconds.
58-
Total uint64 `json:"total,omitempty"`
59-
Percpu []uint64 `json:"percpu,omitempty"`
60-
Kernel uint64 `json:"kernel"`
61-
User uint64 `json:"user"`
58+
Total uint64 `json:"total,omitempty"`
59+
Percpu []uint64 `json:"percpu,omitempty"`
60+
PercpuKernel []uint64 `json:"percpuKernel,omitempty"`
61+
PercpuUser []uint64 `json:"percpuUser,omitempty"`
62+
Kernel uint64 `json:"kernel"`
63+
User uint64 `json:"user"`
6264
}
6365

6466
type Cpu struct {

0 commit comments

Comments
 (0)