Skip to content

Commit 0037985

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 56aca5a commit 0037985

File tree

6 files changed

+163
-5
lines changed

6 files changed

+163
-5
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+
usageKernelMode := []uint64{}
141+
usageUserMode := []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+
usageKernelMode = append(usageKernelMode, 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+
usageUserMode = append(usageUserMode, 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 usageKernelMode, usageUserMode, 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: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,3 +131,41 @@ func expectPageUsageByNUMAEquals(t *testing.T, expected, actual cgroups.PageUsag
131131
t.Errorf("Expected hierarchical total page usage by NUMA %#v but found %#v", expected.Hierarchical.Unevictable, actual.Hierarchical.Unevictable)
132132
}
133133
}
134+
135+
func expectCPUUsageEqual(t *testing.T, expected, actual cgroups.CpuUsage) {
136+
if expected.TotalUsage != actual.TotalUsage {
137+
t.Errorf("Expected CPU total usage %d but found %d\n",
138+
expected.TotalUsage, actual.TotalUsage)
139+
}
140+
141+
for cpuID, actualCPUUsage := range actual.PercpuUsage {
142+
if expected.PercpuUsage[cpuID] != actualCPUUsage {
143+
t.Errorf("Expected CPU%d usage %d but found %d\n",
144+
cpuID, expected.PercpuUsage[cpuID], actualCPUUsage)
145+
}
146+
}
147+
148+
for cpuID, actualKernelModeUsage := range actual.PercpuUsageInKernelmode {
149+
if expected.PercpuUsageInKernelmode[cpuID] != actualKernelModeUsage {
150+
t.Errorf("Expected CPU%d usage in kernel mode %d but found %d\n",
151+
cpuID, expected.PercpuUsageInKernelmode[cpuID], actualKernelModeUsage)
152+
}
153+
}
154+
155+
for cpuID, actualUserModeUsage := range actual.PercpuUsageInUsermode {
156+
if expected.PercpuUsageInUsermode[cpuID] != actualUserModeUsage {
157+
t.Errorf("Expected CPU%d usage in user mode %d but found %d\n",
158+
cpuID, expected.PercpuUsageInUsermode[cpuID], actualUserModeUsage)
159+
}
160+
}
161+
162+
if expected.UsageInKernelmode != actual.UsageInKernelmode {
163+
t.Errorf("Expected CPU usage in kernel mode %d but found %d\n",
164+
expected.UsageInKernelmode, actual.UsageInKernelmode)
165+
}
166+
167+
if expected.UsageInUsermode != actual.UsageInUsermode {
168+
t.Errorf("Expected CPU usage in user mode %d but found %d\n",
169+
expected.UsageInUsermode, actual.UsageInUsermode)
170+
}
171+
}

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:"percpu_kernel,omitempty"`
61+
PercpuUser []uint64 `json:"percpu_user,omitempty"`
62+
Kernel uint64 `json:"kernel"`
63+
User uint64 `json:"user"`
6264
}
6365

6466
type Cpu struct {

0 commit comments

Comments
 (0)