Skip to content

Commit e0c56cb

Browse files
authored
Merge pull request #50 from kolyshkin/fix-usage-all
fs: fix/improve cpuacct.usage_all parsing
2 parents c63eee3 + 5777053 commit e0c56cb

File tree

2 files changed

+57
-4
lines changed

2 files changed

+57
-4
lines changed

fs/cpuacct.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -129,12 +129,16 @@ func getPercpuUsageInModes(path string) ([]uint64, []uint64, error) {
129129
defer fd.Close()
130130

131131
scanner := bufio.NewScanner(fd)
132-
scanner.Scan() // skipping header line
132+
scanner.Scan() // Read header line.
133+
const want = "cpu user system"
134+
if hdr := scanner.Text(); !strings.HasPrefix(hdr, want) {
135+
return nil, nil, malformedLine(path, file, hdr)
136+
}
133137

134138
for scanner.Scan() {
135-
// Each line is: cpu user system
136-
fields := strings.SplitN(scanner.Text(), " ", 3)
137-
if len(fields) != 3 {
139+
// Each line is: cpu user system. Keep N at 4 to ignore extra fields.
140+
fields := strings.SplitN(scanner.Text(), " ", 4)
141+
if len(fields) < 3 {
138142
continue
139143
}
140144

fs/cpuacct_test.go

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package fs
22

33
import (
44
"reflect"
5+
"slices"
56
"testing"
67

78
"github.com/opencontainers/cgroups"
@@ -96,6 +97,54 @@ func TestCpuacctStatsWithoutUsageAll(t *testing.T) {
9697
}
9798
}
9899

100+
// TestCpuacctUsageAllExtra checks that if there are extra columns
101+
// in cpuacct.usage_all, yet the first three are as expected, we
102+
// can still parse it successfully.
103+
func TestCpuacctUsageAllExtra(t *testing.T) {
104+
path := tempDir(t, "cpuacct")
105+
// These extra columns come from the custom Tencent kernel,
106+
// see https://github.com/OpenCloudOS/TencentOS-kernel-0/commit/0b667819c3aaa9c8ac904c6b03256b86be93fc05
107+
err := cgroups.WriteFile(path, "cpuacct.usage_all",
108+
`cpu user system bt_user bt_system
109+
0 962250696038415 637727786389114 0 0
110+
1 981956408513304 638197595421064 0 0
111+
`)
112+
if err != nil {
113+
t.Fatal(err)
114+
}
115+
116+
system, user, err := getPercpuUsageInModes(path)
117+
if err != nil {
118+
t.Fatal(err)
119+
}
120+
121+
expUser := []uint64{962250696038415, 981956408513304}
122+
expSystem := []uint64{637727786389114, 638197595421064}
123+
if !slices.Equal(user, expUser) {
124+
t.Fatalf("unexpected user data (want %+v, got %+v", expUser, user)
125+
}
126+
if !slices.Equal(system, expSystem) {
127+
t.Fatalf("unexpected system data (want %+v, got +%v)", expSystem, system)
128+
}
129+
}
130+
131+
func TestCpuacctUsageAllBad(t *testing.T) {
132+
path := tempDir(t, "cpuacct")
133+
err := cgroups.WriteFile(path, "cpuacct.usage_all",
134+
`cpu bad data fields
135+
0 1 2
136+
`)
137+
if err != nil {
138+
t.Fatal(err)
139+
}
140+
141+
_, _, err = getPercpuUsageInModes(path)
142+
t.Log(err)
143+
if err == nil {
144+
t.Fatal("want error, got nil")
145+
}
146+
}
147+
99148
func BenchmarkGetCpuUsageBreakdown(b *testing.B) {
100149
path := tempDir(b, "cpuacct")
101150
writeFileContents(b, path, map[string]string{

0 commit comments

Comments
 (0)