blob: 2bc0ef3427d2cdb6171010e728537aa3ad91a489 [file] [log] [blame]
Matthias Andreas Benkard832a54e2019-01-29 09:27:38 +01001// Copyright 2017 The Prometheus Authors
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6// http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14package xfs
15
16import (
17 "bufio"
18 "fmt"
19 "io"
20 "strings"
21
22 "github.com/prometheus/procfs/internal/util"
23)
24
25// ParseStats parses a Stats from an input io.Reader, using the format
26// found in /proc/fs/xfs/stat.
27func ParseStats(r io.Reader) (*Stats, error) {
28 const (
29 // Fields parsed into stats structures.
30 fieldExtentAlloc = "extent_alloc"
31 fieldAbt = "abt"
32 fieldBlkMap = "blk_map"
33 fieldBmbt = "bmbt"
34 fieldDir = "dir"
35 fieldTrans = "trans"
36 fieldIg = "ig"
37 fieldLog = "log"
38 fieldRw = "rw"
39 fieldAttr = "attr"
40 fieldIcluster = "icluster"
41 fieldVnodes = "vnodes"
42 fieldBuf = "buf"
43 fieldXpc = "xpc"
44
45 // Unimplemented at this time due to lack of documentation.
46 fieldPushAil = "push_ail"
47 fieldXstrat = "xstrat"
48 fieldAbtb2 = "abtb2"
49 fieldAbtc2 = "abtc2"
50 fieldBmbt2 = "bmbt2"
51 fieldIbt2 = "ibt2"
52 fieldFibt2 = "fibt2"
53 fieldQm = "qm"
54 fieldDebug = "debug"
55 )
56
57 var xfss Stats
58
59 s := bufio.NewScanner(r)
60 for s.Scan() {
61 // Expect at least a string label and a single integer value, ex:
62 // - abt 0
63 // - rw 1 2
64 ss := strings.Fields(string(s.Bytes()))
65 if len(ss) < 2 {
66 continue
67 }
68 label := ss[0]
69
70 // Extended precision counters are uint64 values.
71 if label == fieldXpc {
72 us, err := util.ParseUint64s(ss[1:])
73 if err != nil {
74 return nil, err
75 }
76
77 xfss.ExtendedPrecision, err = extendedPrecisionStats(us)
78 if err != nil {
79 return nil, err
80 }
81
82 continue
83 }
84
85 // All other counters are uint32 values.
86 us, err := util.ParseUint32s(ss[1:])
87 if err != nil {
88 return nil, err
89 }
90
91 switch label {
92 case fieldExtentAlloc:
93 xfss.ExtentAllocation, err = extentAllocationStats(us)
94 case fieldAbt:
95 xfss.AllocationBTree, err = btreeStats(us)
96 case fieldBlkMap:
97 xfss.BlockMapping, err = blockMappingStats(us)
98 case fieldBmbt:
99 xfss.BlockMapBTree, err = btreeStats(us)
100 case fieldDir:
101 xfss.DirectoryOperation, err = directoryOperationStats(us)
102 case fieldTrans:
103 xfss.Transaction, err = transactionStats(us)
104 case fieldIg:
105 xfss.InodeOperation, err = inodeOperationStats(us)
106 case fieldLog:
107 xfss.LogOperation, err = logOperationStats(us)
108 case fieldRw:
109 xfss.ReadWrite, err = readWriteStats(us)
110 case fieldAttr:
111 xfss.AttributeOperation, err = attributeOperationStats(us)
112 case fieldIcluster:
113 xfss.InodeClustering, err = inodeClusteringStats(us)
114 case fieldVnodes:
115 xfss.Vnode, err = vnodeStats(us)
116 case fieldBuf:
117 xfss.Buffer, err = bufferStats(us)
118 }
119 if err != nil {
120 return nil, err
121 }
122 }
123
124 return &xfss, s.Err()
125}
126
127// extentAllocationStats builds an ExtentAllocationStats from a slice of uint32s.
128func extentAllocationStats(us []uint32) (ExtentAllocationStats, error) {
129 if l := len(us); l != 4 {
130 return ExtentAllocationStats{}, fmt.Errorf("incorrect number of values for XFS extent allocation stats: %d", l)
131 }
132
133 return ExtentAllocationStats{
134 ExtentsAllocated: us[0],
135 BlocksAllocated: us[1],
136 ExtentsFreed: us[2],
137 BlocksFreed: us[3],
138 }, nil
139}
140
141// btreeStats builds a BTreeStats from a slice of uint32s.
142func btreeStats(us []uint32) (BTreeStats, error) {
143 if l := len(us); l != 4 {
144 return BTreeStats{}, fmt.Errorf("incorrect number of values for XFS btree stats: %d", l)
145 }
146
147 return BTreeStats{
148 Lookups: us[0],
149 Compares: us[1],
150 RecordsInserted: us[2],
151 RecordsDeleted: us[3],
152 }, nil
153}
154
155// BlockMappingStat builds a BlockMappingStats from a slice of uint32s.
156func blockMappingStats(us []uint32) (BlockMappingStats, error) {
157 if l := len(us); l != 7 {
158 return BlockMappingStats{}, fmt.Errorf("incorrect number of values for XFS block mapping stats: %d", l)
159 }
160
161 return BlockMappingStats{
162 Reads: us[0],
163 Writes: us[1],
164 Unmaps: us[2],
165 ExtentListInsertions: us[3],
166 ExtentListDeletions: us[4],
167 ExtentListLookups: us[5],
168 ExtentListCompares: us[6],
169 }, nil
170}
171
172// DirectoryOperationStats builds a DirectoryOperationStats from a slice of uint32s.
173func directoryOperationStats(us []uint32) (DirectoryOperationStats, error) {
174 if l := len(us); l != 4 {
175 return DirectoryOperationStats{}, fmt.Errorf("incorrect number of values for XFS directory operation stats: %d", l)
176 }
177
178 return DirectoryOperationStats{
179 Lookups: us[0],
180 Creates: us[1],
181 Removes: us[2],
182 Getdents: us[3],
183 }, nil
184}
185
186// TransactionStats builds a TransactionStats from a slice of uint32s.
187func transactionStats(us []uint32) (TransactionStats, error) {
188 if l := len(us); l != 3 {
189 return TransactionStats{}, fmt.Errorf("incorrect number of values for XFS transaction stats: %d", l)
190 }
191
192 return TransactionStats{
193 Sync: us[0],
194 Async: us[1],
195 Empty: us[2],
196 }, nil
197}
198
199// InodeOperationStats builds an InodeOperationStats from a slice of uint32s.
200func inodeOperationStats(us []uint32) (InodeOperationStats, error) {
201 if l := len(us); l != 7 {
202 return InodeOperationStats{}, fmt.Errorf("incorrect number of values for XFS inode operation stats: %d", l)
203 }
204
205 return InodeOperationStats{
206 Attempts: us[0],
207 Found: us[1],
208 Recycle: us[2],
209 Missed: us[3],
210 Duplicate: us[4],
211 Reclaims: us[5],
212 AttributeChange: us[6],
213 }, nil
214}
215
216// LogOperationStats builds a LogOperationStats from a slice of uint32s.
217func logOperationStats(us []uint32) (LogOperationStats, error) {
218 if l := len(us); l != 5 {
219 return LogOperationStats{}, fmt.Errorf("incorrect number of values for XFS log operation stats: %d", l)
220 }
221
222 return LogOperationStats{
223 Writes: us[0],
224 Blocks: us[1],
225 NoInternalBuffers: us[2],
226 Force: us[3],
227 ForceSleep: us[4],
228 }, nil
229}
230
231// ReadWriteStats builds a ReadWriteStats from a slice of uint32s.
232func readWriteStats(us []uint32) (ReadWriteStats, error) {
233 if l := len(us); l != 2 {
234 return ReadWriteStats{}, fmt.Errorf("incorrect number of values for XFS read write stats: %d", l)
235 }
236
237 return ReadWriteStats{
238 Read: us[0],
239 Write: us[1],
240 }, nil
241}
242
243// AttributeOperationStats builds an AttributeOperationStats from a slice of uint32s.
244func attributeOperationStats(us []uint32) (AttributeOperationStats, error) {
245 if l := len(us); l != 4 {
246 return AttributeOperationStats{}, fmt.Errorf("incorrect number of values for XFS attribute operation stats: %d", l)
247 }
248
249 return AttributeOperationStats{
250 Get: us[0],
251 Set: us[1],
252 Remove: us[2],
253 List: us[3],
254 }, nil
255}
256
257// InodeClusteringStats builds an InodeClusteringStats from a slice of uint32s.
258func inodeClusteringStats(us []uint32) (InodeClusteringStats, error) {
259 if l := len(us); l != 3 {
260 return InodeClusteringStats{}, fmt.Errorf("incorrect number of values for XFS inode clustering stats: %d", l)
261 }
262
263 return InodeClusteringStats{
264 Iflush: us[0],
265 Flush: us[1],
266 FlushInode: us[2],
267 }, nil
268}
269
270// VnodeStats builds a VnodeStats from a slice of uint32s.
271func vnodeStats(us []uint32) (VnodeStats, error) {
272 // The attribute "Free" appears to not be available on older XFS
273 // stats versions. Therefore, 7 or 8 elements may appear in
274 // this slice.
275 l := len(us)
276 if l != 7 && l != 8 {
277 return VnodeStats{}, fmt.Errorf("incorrect number of values for XFS vnode stats: %d", l)
278 }
279
280 s := VnodeStats{
281 Active: us[0],
282 Allocate: us[1],
283 Get: us[2],
284 Hold: us[3],
285 Release: us[4],
286 Reclaim: us[5],
287 Remove: us[6],
288 }
289
290 // Skip adding free, unless it is present. The zero value will
291 // be used in place of an actual count.
292 if l == 7 {
293 return s, nil
294 }
295
296 s.Free = us[7]
297 return s, nil
298}
299
300// BufferStats builds a BufferStats from a slice of uint32s.
301func bufferStats(us []uint32) (BufferStats, error) {
302 if l := len(us); l != 9 {
303 return BufferStats{}, fmt.Errorf("incorrect number of values for XFS buffer stats: %d", l)
304 }
305
306 return BufferStats{
307 Get: us[0],
308 Create: us[1],
309 GetLocked: us[2],
310 GetLockedWaited: us[3],
311 BusyLocked: us[4],
312 MissLocked: us[5],
313 PageRetries: us[6],
314 PageFound: us[7],
315 GetRead: us[8],
316 }, nil
317}
318
319// ExtendedPrecisionStats builds an ExtendedPrecisionStats from a slice of uint32s.
320func extendedPrecisionStats(us []uint64) (ExtendedPrecisionStats, error) {
321 if l := len(us); l != 3 {
322 return ExtendedPrecisionStats{}, fmt.Errorf("incorrect number of values for XFS extended precision stats: %d", l)
323 }
324
325 return ExtendedPrecisionStats{
326 FlushBytes: us[0],
327 WriteBytes: us[1],
328 ReadBytes: us[2],
329 }, nil
330}