mirror of https://github.com/gogits/gogs.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
330 lines
8.9 KiB
330 lines
8.9 KiB
// Copyright 2017 The Prometheus Authors |
|
// Licensed under the Apache License, Version 2.0 (the "License"); |
|
// you may not use this file except in compliance with the License. |
|
// You may obtain a copy of the License at |
|
// |
|
// http://www.apache.org/licenses/LICENSE-2.0 |
|
// |
|
// Unless required by applicable law or agreed to in writing, software |
|
// distributed under the License is distributed on an "AS IS" BASIS, |
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
// See the License for the specific language governing permissions and |
|
// limitations under the License. |
|
|
|
package xfs |
|
|
|
import ( |
|
"bufio" |
|
"fmt" |
|
"io" |
|
"strings" |
|
|
|
"github.com/prometheus/procfs/internal/util" |
|
) |
|
|
|
// ParseStats parses a Stats from an input io.Reader, using the format |
|
// found in /proc/fs/xfs/stat. |
|
func ParseStats(r io.Reader) (*Stats, error) { |
|
const ( |
|
// Fields parsed into stats structures. |
|
fieldExtentAlloc = "extent_alloc" |
|
fieldAbt = "abt" |
|
fieldBlkMap = "blk_map" |
|
fieldBmbt = "bmbt" |
|
fieldDir = "dir" |
|
fieldTrans = "trans" |
|
fieldIg = "ig" |
|
fieldLog = "log" |
|
fieldRw = "rw" |
|
fieldAttr = "attr" |
|
fieldIcluster = "icluster" |
|
fieldVnodes = "vnodes" |
|
fieldBuf = "buf" |
|
fieldXpc = "xpc" |
|
|
|
// Unimplemented at this time due to lack of documentation. |
|
fieldPushAil = "push_ail" |
|
fieldXstrat = "xstrat" |
|
fieldAbtb2 = "abtb2" |
|
fieldAbtc2 = "abtc2" |
|
fieldBmbt2 = "bmbt2" |
|
fieldIbt2 = "ibt2" |
|
fieldFibt2 = "fibt2" |
|
fieldQm = "qm" |
|
fieldDebug = "debug" |
|
) |
|
|
|
var xfss Stats |
|
|
|
s := bufio.NewScanner(r) |
|
for s.Scan() { |
|
// Expect at least a string label and a single integer value, ex: |
|
// - abt 0 |
|
// - rw 1 2 |
|
ss := strings.Fields(string(s.Bytes())) |
|
if len(ss) < 2 { |
|
continue |
|
} |
|
label := ss[0] |
|
|
|
// Extended precision counters are uint64 values. |
|
if label == fieldXpc { |
|
us, err := util.ParseUint64s(ss[1:]) |
|
if err != nil { |
|
return nil, err |
|
} |
|
|
|
xfss.ExtendedPrecision, err = extendedPrecisionStats(us) |
|
if err != nil { |
|
return nil, err |
|
} |
|
|
|
continue |
|
} |
|
|
|
// All other counters are uint32 values. |
|
us, err := util.ParseUint32s(ss[1:]) |
|
if err != nil { |
|
return nil, err |
|
} |
|
|
|
switch label { |
|
case fieldExtentAlloc: |
|
xfss.ExtentAllocation, err = extentAllocationStats(us) |
|
case fieldAbt: |
|
xfss.AllocationBTree, err = btreeStats(us) |
|
case fieldBlkMap: |
|
xfss.BlockMapping, err = blockMappingStats(us) |
|
case fieldBmbt: |
|
xfss.BlockMapBTree, err = btreeStats(us) |
|
case fieldDir: |
|
xfss.DirectoryOperation, err = directoryOperationStats(us) |
|
case fieldTrans: |
|
xfss.Transaction, err = transactionStats(us) |
|
case fieldIg: |
|
xfss.InodeOperation, err = inodeOperationStats(us) |
|
case fieldLog: |
|
xfss.LogOperation, err = logOperationStats(us) |
|
case fieldRw: |
|
xfss.ReadWrite, err = readWriteStats(us) |
|
case fieldAttr: |
|
xfss.AttributeOperation, err = attributeOperationStats(us) |
|
case fieldIcluster: |
|
xfss.InodeClustering, err = inodeClusteringStats(us) |
|
case fieldVnodes: |
|
xfss.Vnode, err = vnodeStats(us) |
|
case fieldBuf: |
|
xfss.Buffer, err = bufferStats(us) |
|
} |
|
if err != nil { |
|
return nil, err |
|
} |
|
} |
|
|
|
return &xfss, s.Err() |
|
} |
|
|
|
// extentAllocationStats builds an ExtentAllocationStats from a slice of uint32s. |
|
func extentAllocationStats(us []uint32) (ExtentAllocationStats, error) { |
|
if l := len(us); l != 4 { |
|
return ExtentAllocationStats{}, fmt.Errorf("incorrect number of values for XFS extent allocation stats: %d", l) |
|
} |
|
|
|
return ExtentAllocationStats{ |
|
ExtentsAllocated: us[0], |
|
BlocksAllocated: us[1], |
|
ExtentsFreed: us[2], |
|
BlocksFreed: us[3], |
|
}, nil |
|
} |
|
|
|
// btreeStats builds a BTreeStats from a slice of uint32s. |
|
func btreeStats(us []uint32) (BTreeStats, error) { |
|
if l := len(us); l != 4 { |
|
return BTreeStats{}, fmt.Errorf("incorrect number of values for XFS btree stats: %d", l) |
|
} |
|
|
|
return BTreeStats{ |
|
Lookups: us[0], |
|
Compares: us[1], |
|
RecordsInserted: us[2], |
|
RecordsDeleted: us[3], |
|
}, nil |
|
} |
|
|
|
// BlockMappingStat builds a BlockMappingStats from a slice of uint32s. |
|
func blockMappingStats(us []uint32) (BlockMappingStats, error) { |
|
if l := len(us); l != 7 { |
|
return BlockMappingStats{}, fmt.Errorf("incorrect number of values for XFS block mapping stats: %d", l) |
|
} |
|
|
|
return BlockMappingStats{ |
|
Reads: us[0], |
|
Writes: us[1], |
|
Unmaps: us[2], |
|
ExtentListInsertions: us[3], |
|
ExtentListDeletions: us[4], |
|
ExtentListLookups: us[5], |
|
ExtentListCompares: us[6], |
|
}, nil |
|
} |
|
|
|
// DirectoryOperationStats builds a DirectoryOperationStats from a slice of uint32s. |
|
func directoryOperationStats(us []uint32) (DirectoryOperationStats, error) { |
|
if l := len(us); l != 4 { |
|
return DirectoryOperationStats{}, fmt.Errorf("incorrect number of values for XFS directory operation stats: %d", l) |
|
} |
|
|
|
return DirectoryOperationStats{ |
|
Lookups: us[0], |
|
Creates: us[1], |
|
Removes: us[2], |
|
Getdents: us[3], |
|
}, nil |
|
} |
|
|
|
// TransactionStats builds a TransactionStats from a slice of uint32s. |
|
func transactionStats(us []uint32) (TransactionStats, error) { |
|
if l := len(us); l != 3 { |
|
return TransactionStats{}, fmt.Errorf("incorrect number of values for XFS transaction stats: %d", l) |
|
} |
|
|
|
return TransactionStats{ |
|
Sync: us[0], |
|
Async: us[1], |
|
Empty: us[2], |
|
}, nil |
|
} |
|
|
|
// InodeOperationStats builds an InodeOperationStats from a slice of uint32s. |
|
func inodeOperationStats(us []uint32) (InodeOperationStats, error) { |
|
if l := len(us); l != 7 { |
|
return InodeOperationStats{}, fmt.Errorf("incorrect number of values for XFS inode operation stats: %d", l) |
|
} |
|
|
|
return InodeOperationStats{ |
|
Attempts: us[0], |
|
Found: us[1], |
|
Recycle: us[2], |
|
Missed: us[3], |
|
Duplicate: us[4], |
|
Reclaims: us[5], |
|
AttributeChange: us[6], |
|
}, nil |
|
} |
|
|
|
// LogOperationStats builds a LogOperationStats from a slice of uint32s. |
|
func logOperationStats(us []uint32) (LogOperationStats, error) { |
|
if l := len(us); l != 5 { |
|
return LogOperationStats{}, fmt.Errorf("incorrect number of values for XFS log operation stats: %d", l) |
|
} |
|
|
|
return LogOperationStats{ |
|
Writes: us[0], |
|
Blocks: us[1], |
|
NoInternalBuffers: us[2], |
|
Force: us[3], |
|
ForceSleep: us[4], |
|
}, nil |
|
} |
|
|
|
// ReadWriteStats builds a ReadWriteStats from a slice of uint32s. |
|
func readWriteStats(us []uint32) (ReadWriteStats, error) { |
|
if l := len(us); l != 2 { |
|
return ReadWriteStats{}, fmt.Errorf("incorrect number of values for XFS read write stats: %d", l) |
|
} |
|
|
|
return ReadWriteStats{ |
|
Read: us[0], |
|
Write: us[1], |
|
}, nil |
|
} |
|
|
|
// AttributeOperationStats builds an AttributeOperationStats from a slice of uint32s. |
|
func attributeOperationStats(us []uint32) (AttributeOperationStats, error) { |
|
if l := len(us); l != 4 { |
|
return AttributeOperationStats{}, fmt.Errorf("incorrect number of values for XFS attribute operation stats: %d", l) |
|
} |
|
|
|
return AttributeOperationStats{ |
|
Get: us[0], |
|
Set: us[1], |
|
Remove: us[2], |
|
List: us[3], |
|
}, nil |
|
} |
|
|
|
// InodeClusteringStats builds an InodeClusteringStats from a slice of uint32s. |
|
func inodeClusteringStats(us []uint32) (InodeClusteringStats, error) { |
|
if l := len(us); l != 3 { |
|
return InodeClusteringStats{}, fmt.Errorf("incorrect number of values for XFS inode clustering stats: %d", l) |
|
} |
|
|
|
return InodeClusteringStats{ |
|
Iflush: us[0], |
|
Flush: us[1], |
|
FlushInode: us[2], |
|
}, nil |
|
} |
|
|
|
// VnodeStats builds a VnodeStats from a slice of uint32s. |
|
func vnodeStats(us []uint32) (VnodeStats, error) { |
|
// The attribute "Free" appears to not be available on older XFS |
|
// stats versions. Therefore, 7 or 8 elements may appear in |
|
// this slice. |
|
l := len(us) |
|
if l != 7 && l != 8 { |
|
return VnodeStats{}, fmt.Errorf("incorrect number of values for XFS vnode stats: %d", l) |
|
} |
|
|
|
s := VnodeStats{ |
|
Active: us[0], |
|
Allocate: us[1], |
|
Get: us[2], |
|
Hold: us[3], |
|
Release: us[4], |
|
Reclaim: us[5], |
|
Remove: us[6], |
|
} |
|
|
|
// Skip adding free, unless it is present. The zero value will |
|
// be used in place of an actual count. |
|
if l == 7 { |
|
return s, nil |
|
} |
|
|
|
s.Free = us[7] |
|
return s, nil |
|
} |
|
|
|
// BufferStats builds a BufferStats from a slice of uint32s. |
|
func bufferStats(us []uint32) (BufferStats, error) { |
|
if l := len(us); l != 9 { |
|
return BufferStats{}, fmt.Errorf("incorrect number of values for XFS buffer stats: %d", l) |
|
} |
|
|
|
return BufferStats{ |
|
Get: us[0], |
|
Create: us[1], |
|
GetLocked: us[2], |
|
GetLockedWaited: us[3], |
|
BusyLocked: us[4], |
|
MissLocked: us[5], |
|
PageRetries: us[6], |
|
PageFound: us[7], |
|
GetRead: us[8], |
|
}, nil |
|
} |
|
|
|
// ExtendedPrecisionStats builds an ExtendedPrecisionStats from a slice of uint32s. |
|
func extendedPrecisionStats(us []uint64) (ExtendedPrecisionStats, error) { |
|
if l := len(us); l != 3 { |
|
return ExtendedPrecisionStats{}, fmt.Errorf("incorrect number of values for XFS extended precision stats: %d", l) |
|
} |
|
|
|
return ExtendedPrecisionStats{ |
|
FlushBytes: us[0], |
|
WriteBytes: us[1], |
|
ReadBytes: us[2], |
|
}, nil |
|
}
|
|
|