mirror of
				https://gitea.com/Lydanne/buildx.git
				synced 2025-10-31 16:13:45 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			331 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			331 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| // 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
 | |
| }
 | 
