Skip to content

Commit e313314

Browse files
committed
fs2: add iocost statistics
When the iocost controller is enabled it will emit statistics about its usage in io.stat. Export this when available. This is a no-op when iocost is not enabled. There is a comment that we only expose data which directly maps to cgroups v1. We're already breaking this by adding PSI metrics, so reword this to just indicate that we currently don't recognize the other fields. Signed-off-by: Morten Hein Tiljeset <[email protected]>
1 parent 2f41057 commit e313314

File tree

3 files changed

+91
-18
lines changed

3 files changed

+91
-18
lines changed

fs2/io.go

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -165,11 +165,22 @@ func statIo(dirPath string, stats *cgroups.Stats) error {
165165
case "wios":
166166
op = "Write"
167167
targetTable = &parsedStats.IoServicedRecursive
168+
169+
case "cost.usage":
170+
op = "Count"
171+
targetTable = &parsedStats.IoCostUsage
172+
case "cost.wait":
173+
op = "Count"
174+
targetTable = &parsedStats.IoCostWait
175+
case "cost.indebt":
176+
op = "Count"
177+
targetTable = &parsedStats.IoCostIndebt
178+
case "cost.indelay":
179+
op = "Count"
180+
targetTable = &parsedStats.IoCostIndelay
181+
168182
default:
169-
// Skip over entries we cannot map to cgroupv1 stats for now.
170-
// In the future we should expand the stats struct to include
171-
// them.
172-
logrus.Debugf("cgroupv2 io stats: skipping over unmappable %s entry", item)
183+
logrus.Debugf("cgroupv2 io stats: unknown entry %s", item)
173184
continue
174185
}
175186

fs2/io_test.go

Lines changed: 72 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ const exampleIoStatData = `254:1 rbytes=6901432320 wbytes=14245535744 rios=26327
1414
254:0 rbytes=2702336 wbytes=0 rios=97 wios=0 dbytes=0 dios=0
1515
259:0 rbytes=6911345664 wbytes=14245536256 rios=264538 wios=244914 dbytes=530485248 dios=2`
1616

17+
const exampleIoCostDebugData = `251:0 rbytes=2285568 wbytes=688128 rios=107 wios=168 dbytes=0 dios=0
18+
252:0 rbytes=2037743988736 wbytes=1036567117824 rios=169193849 wios=41541021 dbytes=1012840136704 dios=199909
19+
259:0 rbytes=4085926524416 wbytes=1036680064512 rios=185034771 wios=40358485 dbytes=1013982564352 dios=199959 cost.vrate=100.00 cost.usage=1532009788 cost.wait=1477289869 cost.indebt=0 cost.indelay=0`
20+
1721
var exampleIoStatsParsed = cgroups.BlkioStats{
1822
IoServiceBytesRecursive: []cgroups.BlkioStatEntry{
1923
{Major: 254, Minor: 1, Value: 6901432320, Op: "Read"},
@@ -33,6 +37,37 @@ var exampleIoStatsParsed = cgroups.BlkioStats{
3337
},
3438
}
3539

40+
var exampleIoCostDebugParsed = cgroups.BlkioStats{
41+
IoServiceBytesRecursive: []cgroups.BlkioStatEntry{
42+
{Major: 251, Minor: 0, Value: 2285568, Op: "Read"},
43+
{Major: 251, Minor: 0, Value: 688128, Op: "Write"},
44+
{Major: 252, Minor: 0, Value: 2037743988736, Op: "Read"},
45+
{Major: 252, Minor: 0, Value: 1036567117824, Op: "Write"},
46+
{Major: 259, Minor: 0, Value: 4085926524416, Op: "Read"},
47+
{Major: 259, Minor: 0, Value: 1036680064512, Op: "Write"},
48+
},
49+
IoServicedRecursive: []cgroups.BlkioStatEntry{
50+
{Major: 251, Minor: 0, Value: 107, Op: "Read"},
51+
{Major: 251, Minor: 0, Value: 168, Op: "Write"},
52+
{Major: 252, Minor: 0, Value: 169193849, Op: "Read"},
53+
{Major: 252, Minor: 0, Value: 41541021, Op: "Write"},
54+
{Major: 259, Minor: 0, Value: 185034771, Op: "Read"},
55+
{Major: 259, Minor: 0, Value: 40358485, Op: "Write"},
56+
},
57+
IoCostUsage: []cgroups.BlkioStatEntry{
58+
{Major: 259, Minor: 0, Value: 1532009788, Op: "Count"},
59+
},
60+
IoCostWait: []cgroups.BlkioStatEntry{
61+
{Major: 259, Minor: 0, Value: 1477289869, Op: "Count"},
62+
},
63+
IoCostIndebt: []cgroups.BlkioStatEntry{
64+
{Major: 259, Minor: 0, Value: 0, Op: "Count"},
65+
},
66+
IoCostIndelay: []cgroups.BlkioStatEntry{
67+
{Major: 259, Minor: 0, Value: 0, Op: "Count"},
68+
},
69+
}
70+
3671
func lessBlkioStatEntry(a, b cgroups.BlkioStatEntry) bool {
3772
if a.Major != b.Major {
3873
return a.Major < b.Major
@@ -56,26 +91,49 @@ func sortBlkioStats(stats *cgroups.BlkioStats) {
5691
}
5792

5893
func TestStatIo(t *testing.T) {
94+
tests := []struct {
95+
name string
96+
input string
97+
expected cgroups.BlkioStats
98+
}{
99+
{
100+
name: "default io.stat case",
101+
input: exampleIoStatData,
102+
expected: exampleIoStatsParsed,
103+
},
104+
{
105+
name: "io.stat with iocost debug data",
106+
input: exampleIoCostDebugData,
107+
expected: exampleIoCostDebugParsed,
108+
},
109+
}
110+
59111
// We're using a fake cgroupfs.
60112
cgroups.TestMode = true
61113

62-
fakeCgroupDir := t.TempDir()
63-
statPath := filepath.Join(fakeCgroupDir, "io.stat")
114+
for _, tt := range tests {
115+
t.Run(tt.name, func(t *testing.T) {
116+
t.Parallel()
64117

65-
if err := os.WriteFile(statPath, []byte(exampleIoStatData), 0o644); err != nil {
66-
t.Fatal(err)
67-
}
118+
fakeCgroupDir := t.TempDir()
119+
statPath := filepath.Join(fakeCgroupDir, "io.stat")
68120

69-
var gotStats cgroups.Stats
70-
if err := statIo(fakeCgroupDir, &gotStats); err != nil {
71-
t.Error(err)
72-
}
121+
if err := os.WriteFile(statPath, []byte(tt.input), 0o644); err != nil {
122+
t.Fatal(err)
123+
}
124+
125+
var gotStats cgroups.Stats
126+
if err := statIo(fakeCgroupDir, &gotStats); err != nil {
127+
t.Error(err)
128+
}
73129

74-
// Sort the output since statIo uses a map internally.
75-
sortBlkioStats(&gotStats.BlkioStats)
76-
sortBlkioStats(&exampleIoStatsParsed)
130+
// Sort the output since statIo uses a map internally.
131+
sortBlkioStats(&gotStats.BlkioStats)
132+
sortBlkioStats(&tt.expected)
77133

78-
if !reflect.DeepEqual(gotStats.BlkioStats, exampleIoStatsParsed) {
79-
t.Errorf("parsed cgroupv2 io.stat doesn't match expected result: \ngot %#v\nexpected %#v\n", gotStats.BlkioStats, exampleIoStatsParsed)
134+
if !reflect.DeepEqual(gotStats.BlkioStats, tt.expected) {
135+
t.Errorf("parsed cgroupv2 io.stat doesn't match expected result: \ngot %#v\nexpected %#v\n", gotStats.BlkioStats, tt.expected)
136+
}
137+
})
80138
}
81139
}

stats.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,10 @@ type BlkioStats struct {
159159
IoTimeRecursive []BlkioStatEntry `json:"io_time_recursive,omitempty"`
160160
SectorsRecursive []BlkioStatEntry `json:"sectors_recursive,omitempty"`
161161
PSI *PSIStats `json:"psi,omitempty"`
162+
IoCostUsage []BlkioStatEntry `json:"io_cost_usage,omitempty"`
163+
IoCostWait []BlkioStatEntry `json:"io_cost_wait,omitempty"`
164+
IoCostIndebt []BlkioStatEntry `json:"io_cost_indebt,omitempty"`
165+
IoCostIndelay []BlkioStatEntry `json:"io_cost_indelay,omitempty"`
162166
}
163167

164168
type HugetlbStats struct {

0 commit comments

Comments
 (0)