123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518 |
- // 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"
- fieldPushAil = "push_ail"
- fieldXstrat = "xstrat"
- fieldRw = "rw"
- fieldAttr = "attr"
- fieldIcluster = "icluster"
- fieldVnodes = "vnodes"
- fieldBuf = "buf"
- fieldXpc = "xpc"
- fieldAbtb2 = "abtb2"
- fieldAbtc2 = "abtc2"
- fieldBmbt2 = "bmbt2"
- fieldIbt2 = "ibt2"
- //fieldFibt2 = "fibt2"
- fieldQm = "qm"
- fieldDebug = "debug"
- // Unimplemented at this time due to lack of documentation.
- //fieldRmapbt = "rmapbt"
- //fieldRefcntbt = "refcntbt"
- )
- 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)
- case fieldPushAil:
- xfss.PushAil, err = pushAilStats(us)
- case fieldXstrat:
- xfss.Xstrat, err = xStratStats(us)
- case fieldAbtb2:
- xfss.BtreeAllocBlocks2, err = btreeAllocBlocks2Stats(us)
- case fieldAbtc2:
- xfss.BtreeAllocContig2, err = btreeAllocContig2Stats(us)
- case fieldBmbt2:
- xfss.BtreeBlockMap2, err = btreeBlockMap2Stats(us)
- case fieldIbt2:
- xfss.BtreeInode2, err = btreeInode2Stats(us)
- //case fieldFibt2:
- case fieldQm:
- xfss.QuotaManager, err = quotaManagerStats(us)
- case fieldDebug:
- xfss.Debug, err = debugStats(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
- }
- // pushAilStats handles push_ail stats.
- func pushAilStats(us []uint32) (PushAilStats, error) {
- if l := len(us); l != 10 {
- return PushAilStats{}, fmt.Errorf("incorrect number of values for XFS push ail stats: %d", l)
- }
- return PushAilStats{
- TryLogspace: us[0],
- SleepLogspace: us[1],
- Pushes: us[2],
- Success: us[3],
- PushBuf: us[4],
- Pinned: us[5],
- Locked: us[6],
- Flushing: us[7],
- Restarts: us[8],
- Flush: us[9],
- }, nil
- }
- // xStratStats handles xstrat stats.
- func xStratStats(us []uint32) (XstratStats, error) {
- if l := len(us); l != 2 {
- return XstratStats{}, fmt.Errorf("incorrect number of values for XFS xstrat stats: %d", l)
- }
- return XstratStats{
- Quick: us[0],
- Split: us[1],
- }, nil
- }
- // readWriteStats handles rw stats.
- 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{
- Write: us[0],
- Read: 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
- }
- func quotaManagerStats(us []uint32) (QuotaManagerStats, error) {
- // The "Unused" attribute first appears in Linux 4.20
- // As a result either 8 or 9 elements may appear in this slice depending on
- // the kernel version.
- l := len(us)
- if l != 8 && l != 9 {
- return QuotaManagerStats{}, fmt.Errorf("incorrect number of values for XFS quota stats: %d", l)
- }
- s := QuotaManagerStats{
- Reclaims: us[0],
- ReclaimMisses: us[1],
- DquoteDups: us[2],
- CacheMisses: us[3],
- CacheHits: us[4],
- Wants: us[5],
- ShakeReclaims: us[6],
- InactReclaims: us[7],
- }
- if l > 8 {
- s.Unused = us[8]
- }
- return s, nil
- }
- func debugStats(us []uint32) (DebugStats, error) {
- if l := len(us); l != 1 {
- return DebugStats{}, fmt.Errorf("incorrect number of values for XFS debug stats: %d", l)
- }
- return DebugStats{
- Enabled: us[0],
- }, nil
- }
- // btreeAllocBlocks2Stats handles abtb2 stats.
- func btreeAllocBlocks2Stats(us []uint32) (BtreeAllocBlocks2Stats, error) {
- if l := len(us); l != 15 {
- return BtreeAllocBlocks2Stats{}, fmt.Errorf("incorrect number of values for abtb2 stats: %d", 1)
- }
- return BtreeAllocBlocks2Stats{
- Lookup: us[0],
- Compare: us[1],
- Insrec: us[2],
- Delrec: us[3],
- NewRoot: us[4],
- KillRoot: us[5],
- Increment: us[6],
- Decrement: us[7],
- Lshift: us[8],
- Rshift: us[9],
- Split: us[10],
- Join: us[11],
- Alloc: us[12],
- Free: us[13],
- Moves: us[14],
- }, nil
- }
- // btreeAllocContig2Stats handles abtc2 stats.
- func btreeAllocContig2Stats(us []uint32) (BtreeAllocContig2Stats, error) {
- if l := len(us); l != 15 {
- return BtreeAllocContig2Stats{}, fmt.Errorf("incorrect number of values for abtc2 stats: %d", 1)
- }
- return BtreeAllocContig2Stats{
- Lookup: us[0],
- Compare: us[1],
- Insrec: us[2],
- Delrec: us[3],
- NewRoot: us[4],
- KillRoot: us[5],
- Increment: us[6],
- Decrement: us[7],
- Lshift: us[8],
- Rshift: us[9],
- Split: us[10],
- Join: us[11],
- Alloc: us[12],
- Free: us[13],
- Moves: us[14],
- }, nil
- }
- // btreeBlockMap2Stats handles bmbt2 stats.
- func btreeBlockMap2Stats(us []uint32) (BtreeBlockMap2Stats, error) {
- if l := len(us); l != 15 {
- return BtreeBlockMap2Stats{}, fmt.Errorf("incorrect number of values for bmbt2 stats: %d", 1)
- }
- return BtreeBlockMap2Stats{
- Lookup: us[0],
- Compare: us[1],
- Insrec: us[2],
- Delrec: us[3],
- NewRoot: us[4],
- KillRoot: us[5],
- Increment: us[6],
- Decrement: us[7],
- Lshift: us[8],
- Rshift: us[9],
- Split: us[10],
- Join: us[11],
- Alloc: us[12],
- Free: us[13],
- Moves: us[14],
- }, nil
- }
- // btreeInode2Stats handles ibt2 stats.
- func btreeInode2Stats(us []uint32) (BtreeInode2Stats, error) {
- if l := len(us); l != 15 {
- return BtreeInode2Stats{}, fmt.Errorf("incorrect number of values for ibt2 stats: %d", 1)
- }
- return BtreeInode2Stats{
- Lookup: us[0],
- Compare: us[1],
- Insrec: us[2],
- Delrec: us[3],
- NewRoot: us[4],
- KillRoot: us[5],
- Increment: us[6],
- Decrement: us[7],
- Lshift: us[8],
- Rshift: us[9],
- Split: us[10],
- Join: us[11],
- Alloc: us[12],
- Free: us[13],
- Moves: us[14],
- }, nil
- }
|