@@ -12,8 +12,10 @@ import (
12
12
)
13
13
14
14
const (
15
- cgroupV2CPUMax = "/sys/fs/cgroup/cpu.max"
16
- cgroupV2CPUStat = "/sys/fs/cgroup/cpu.stat"
15
+ cgroupV1CPUAcctUsage = "/sys/fs/cgroup/cpu,cpuacct/cpuacct.usage"
16
+ cgroupV1CFSQuotaUs = "/sys/fs/cgroup/cpu,cpuacct/cpu.cfs_quota_us"
17
+ cgroupV2CPUMax = "/sys/fs/cgroup/cpu.max"
18
+ cgroupV2CPUStat = "/sys/fs/cgroup/cpu.stat"
17
19
)
18
20
19
21
// ContainerCPU returns the CPU usage of the container cgroup.
@@ -38,8 +40,8 @@ func (s *Statter) ContainerCPU() (*Result, error) {
38
40
39
41
r := & Result {
40
42
Unit : "cores" ,
41
- Used : (used2 - used1 ).Seconds (),
42
- Total : ptr .To (total .Seconds () / s . sampleInterval . Seconds () ), // close enough to the truth
43
+ Used : (used2 - used1 ).Seconds () * s . sampleInterval . Seconds () ,
44
+ Total : ptr .To (total .Seconds ()), // close enough to the truth
43
45
}
44
46
return r , nil
45
47
}
@@ -62,12 +64,12 @@ func (s *Statter) isCGroupV2() bool {
62
64
func (s * Statter ) cGroupV2CPU () (used , total time.Duration , err error ) {
63
65
total , err = s .cGroupv2CPUTotal ()
64
66
if err != nil {
65
- return 0 , 0 , xerrors .Errorf ("get cgroup v2 CPU cores : %w" , err )
67
+ return 0 , 0 , xerrors .Errorf ("get cgroup v2 cpu total : %w" , err )
66
68
}
67
69
68
70
used , err = s .cGroupv2CPUUsed ()
69
71
if err != nil {
70
- return 0 , 0 , xerrors .Errorf ("get cgroup v2 CPU used: %w" , err )
72
+ return 0 , 0 , xerrors .Errorf ("get cgroup v2 cpu used: %w" , err )
71
73
}
72
74
73
75
return used , total , nil
@@ -77,7 +79,7 @@ func (s *Statter) cGroupv2CPUUsed() (used time.Duration, err error) {
77
79
var data []byte
78
80
data , err = afero .ReadFile (s .fs , cgroupV2CPUStat )
79
81
if err != nil {
80
- return 0 , xerrors .Errorf ("read /sys/fs/cgroup/cpu.stat : %w" , err )
82
+ return 0 , xerrors .Errorf ("read %s : %w" , cgroupV2CPUStat , err )
81
83
}
82
84
83
85
bs := bufio .NewScanner (bytes .NewReader (data ))
@@ -89,54 +91,102 @@ func (s *Statter) cGroupv2CPUUsed() (used time.Duration, err error) {
89
91
90
92
parts := bytes .Split (line , []byte (" " ))
91
93
if len (parts ) != 2 {
92
- return 0 , xerrors .Errorf ("unexpected line in /sys/fs/cgroup/cpu.stat : %s" , line )
94
+ return 0 , xerrors .Errorf ("unexpected line in %s : %s" , cgroupV2CPUStat , line )
93
95
}
94
96
95
97
iused , err := strconv .Atoi (string (parts [1 ]))
96
98
if err != nil {
97
- return 0 , xerrors .Errorf ("parse /sys/fs/cgroup/cpu.stat : %w" , err )
99
+ return 0 , xerrors .Errorf ("parse %s : %w" , err , cgroupV2CPUStat )
98
100
}
99
101
100
102
return time .Duration (iused ) * time .Microsecond , nil
101
103
}
102
104
103
- return 0 , xerrors .Errorf ("did not find expected usage_usec in /sys/fs/cgroup/cpu.stat" )
105
+ return 0 , xerrors .Errorf ("did not find expected usage_usec in %s" , cgroupV2CPUStat )
104
106
}
105
107
106
108
func (s * Statter ) cGroupv2CPUTotal () (total time.Duration , err error ) {
107
109
var data []byte
108
- var quotaUs int
109
- data , err = afero .ReadFile (s .fs , "/sys/fs/cgroup/cpu.max" )
110
+ var quotaUs int64
111
+ data , err = afero .ReadFile (s .fs , cgroupV2CPUMax )
110
112
if err != nil {
111
- return 0 , xerrors .Errorf ("read /sys/fs/cgroup/cpu.max : %w" , err )
113
+ return 0 , xerrors .Errorf ("read %s : %w" , cgroupV2CPUMax , err )
112
114
}
113
115
114
116
lines := bytes .Split (data , []byte ("\n " ))
115
117
if len (lines ) < 1 {
116
- return 0 , xerrors .Errorf ("unexpected empty /sys/fs/cgroup/cpu.max" )
118
+ return 0 , xerrors .Errorf ("unexpected empty %s" , cgroupV2CPUMax )
117
119
}
118
120
119
- line := lines [0 ]
120
- parts := bytes .Split (line , []byte (" " ))
121
+ parts := bytes .Split (lines [0 ], []byte (" " ))
121
122
if len (parts ) != 2 {
122
- return 0 , xerrors .Errorf ("unexpected line in /sys/fs/cgroup/cpu.max : %s" , line )
123
+ return 0 , xerrors .Errorf ("unexpected line in %s : %s" , cgroupV2CPUMax , lines [ 0 ] )
123
124
}
124
125
125
126
if bytes .Equal (parts [0 ], []byte ("max" )) {
126
- quotaUs = s .nproc * int ( time .Second .Microseconds () )
127
+ quotaUs = int64 ( s .nproc ) * time .Second .Microseconds ()
127
128
} else {
128
- quotaUs , err = strconv .Atoi (string (parts [0 ]))
129
+ quotaUs , err = strconv .ParseInt (string (parts [0 ]), 10 , 64 )
129
130
if err != nil {
130
- return 0 , xerrors .Errorf ("parse /sys/fs/cgroup/cpu.max : %w" , err )
131
+ return 0 , xerrors .Errorf ("parse %s : %w" , cgroupV2CPUMax , err )
131
132
}
132
133
}
133
134
134
135
return time .Duration (quotaUs ) * time .Microsecond , nil
135
136
}
136
137
137
- func (* Statter ) cGroupV1CPU () (time.Duration , time.Duration , error ) {
138
- // TODO: implement
139
- return 0 , 0 , nil
138
+ func (s * Statter ) cGroupV1CPU () (used , total time.Duration , err error ) {
139
+ total , err = s .cGroupV1CPUTotal ()
140
+ if err != nil {
141
+ return 0 , 0 , xerrors .Errorf ("get cgroup v1 CPU total: %w" , err )
142
+ }
143
+
144
+ used , err = s .cgroupV1CPUUsed ()
145
+ if err != nil {
146
+ return 0 , 0 , xerrors .Errorf ("get cgruop v1 cpu used: %w" , err )
147
+ }
148
+
149
+ return used , total , nil
150
+ }
151
+
152
+ func (s * Statter ) cGroupV1CPUTotal () (time.Duration , error ) {
153
+ var data []byte
154
+ var err error
155
+ var quotaUs int64
156
+
157
+ data , err = afero .ReadFile (s .fs , cgroupV1CFSQuotaUs )
158
+ if err != nil {
159
+ return 0 , xerrors .Errorf ("read %s: %w" , cgroupV1CFSQuotaUs , err )
160
+ }
161
+
162
+ quotaUs , err = strconv .ParseInt (string (bytes .TrimSpace (data )), 10 , 64 )
163
+ if err != nil {
164
+ return 0 , xerrors .Errorf ("parse %s: %w" , cgroupV1CFSQuotaUs , err )
165
+ }
166
+
167
+ if quotaUs < 0 {
168
+ quotaUs = int64 (s .nproc ) * time .Second .Microseconds ()
169
+ }
170
+
171
+ return time .Duration (quotaUs ) * time .Microsecond , nil
172
+ }
173
+
174
+ func (s * Statter ) cgroupV1CPUUsed () (time.Duration , error ) {
175
+ var data []byte
176
+ var err error
177
+ var usageUs int64
178
+
179
+ data , err = afero .ReadFile (s .fs , cgroupV1CPUAcctUsage )
180
+ if err != nil {
181
+ return 0 , xerrors .Errorf ("read %s: %w" , cgroupV1CPUAcctUsage , err )
182
+ }
183
+
184
+ usageUs , err = strconv .ParseInt (string (bytes .TrimSpace (data )), 10 , 64 )
185
+ if err != nil {
186
+ return 0 , xerrors .Errorf ("parse %s: %w" , cgroupV1CPUAcctUsage , err )
187
+ }
188
+
189
+ return time .Duration (usageUs ) * time .Microsecond , nil
140
190
}
141
191
142
192
// ContainerMemory returns the memory usage of the container cgroup.
0 commit comments