...

Source file src/github.com/prometheus/procfs/xfs/parse.go

Documentation: github.com/prometheus/procfs/xfs

     1  // 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  
    14  package xfs
    15  
    16  import (
    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.
    27  func 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  		fieldPushAil     = "push_ail"
    39  		fieldXstrat      = "xstrat"
    40  		fieldRw          = "rw"
    41  		fieldAttr        = "attr"
    42  		fieldIcluster    = "icluster"
    43  		fieldVnodes      = "vnodes"
    44  		fieldBuf         = "buf"
    45  		fieldXpc         = "xpc"
    46  		fieldAbtb2       = "abtb2"
    47  		fieldAbtc2       = "abtc2"
    48  		fieldBmbt2       = "bmbt2"
    49  		fieldIbt2        = "ibt2"
    50  		//fieldFibt2 = "fibt2"
    51  		fieldQm    = "qm"
    52  		fieldDebug = "debug"
    53  		// Unimplemented at this time due to lack of documentation.
    54  		//fieldRmapbt = "rmapbt"
    55  		//fieldRefcntbt = "refcntbt"
    56  
    57  	)
    58  
    59  	var xfss Stats
    60  
    61  	s := bufio.NewScanner(r)
    62  	for s.Scan() {
    63  		// Expect at least a string label and a single integer value, ex:
    64  		//   - abt 0
    65  		//   - rw 1 2
    66  		ss := strings.Fields(string(s.Bytes()))
    67  		if len(ss) < 2 {
    68  			continue
    69  		}
    70  		label := ss[0]
    71  
    72  		// Extended precision counters are uint64 values.
    73  		if label == fieldXpc {
    74  			us, err := util.ParseUint64s(ss[1:])
    75  			if err != nil {
    76  				return nil, err
    77  			}
    78  
    79  			xfss.ExtendedPrecision, err = extendedPrecisionStats(us)
    80  			if err != nil {
    81  				return nil, err
    82  			}
    83  
    84  			continue
    85  		}
    86  
    87  		// All other counters are uint32 values.
    88  		us, err := util.ParseUint32s(ss[1:])
    89  		if err != nil {
    90  			return nil, err
    91  		}
    92  
    93  		switch label {
    94  		case fieldExtentAlloc:
    95  			xfss.ExtentAllocation, err = extentAllocationStats(us)
    96  		case fieldAbt:
    97  			xfss.AllocationBTree, err = btreeStats(us)
    98  		case fieldBlkMap:
    99  			xfss.BlockMapping, err = blockMappingStats(us)
   100  		case fieldBmbt:
   101  			xfss.BlockMapBTree, err = btreeStats(us)
   102  		case fieldDir:
   103  			xfss.DirectoryOperation, err = directoryOperationStats(us)
   104  		case fieldTrans:
   105  			xfss.Transaction, err = transactionStats(us)
   106  		case fieldIg:
   107  			xfss.InodeOperation, err = inodeOperationStats(us)
   108  		case fieldLog:
   109  			xfss.LogOperation, err = logOperationStats(us)
   110  		case fieldRw:
   111  			xfss.ReadWrite, err = readWriteStats(us)
   112  		case fieldAttr:
   113  			xfss.AttributeOperation, err = attributeOperationStats(us)
   114  		case fieldIcluster:
   115  			xfss.InodeClustering, err = inodeClusteringStats(us)
   116  		case fieldVnodes:
   117  			xfss.Vnode, err = vnodeStats(us)
   118  		case fieldBuf:
   119  			xfss.Buffer, err = bufferStats(us)
   120  		case fieldPushAil:
   121  			xfss.PushAil, err = pushAilStats(us)
   122  		case fieldXstrat:
   123  			xfss.Xstrat, err = xStratStats(us)
   124  		case fieldAbtb2:
   125  			xfss.BtreeAllocBlocks2, err = btreeAllocBlocks2Stats(us)
   126  		case fieldAbtc2:
   127  			xfss.BtreeAllocContig2, err = btreeAllocContig2Stats(us)
   128  		case fieldBmbt2:
   129  			xfss.BtreeBlockMap2, err = btreeBlockMap2Stats(us)
   130  		case fieldIbt2:
   131  			xfss.BtreeInode2, err = btreeInode2Stats(us)
   132  		//case fieldFibt2:
   133  		case fieldQm:
   134  			xfss.QuotaManager, err = quotaManagerStats(us)
   135  		case fieldDebug:
   136  			xfss.Debug, err = debugStats(us)
   137  		}
   138  		if err != nil {
   139  			return nil, err
   140  		}
   141  	}
   142  
   143  	return &xfss, s.Err()
   144  }
   145  
   146  // extentAllocationStats builds an ExtentAllocationStats from a slice of uint32s.
   147  func extentAllocationStats(us []uint32) (ExtentAllocationStats, error) {
   148  	if l := len(us); l != 4 {
   149  		return ExtentAllocationStats{}, fmt.Errorf("incorrect number of values for XFS extent allocation stats: %d", l)
   150  	}
   151  
   152  	return ExtentAllocationStats{
   153  		ExtentsAllocated: us[0],
   154  		BlocksAllocated:  us[1],
   155  		ExtentsFreed:     us[2],
   156  		BlocksFreed:      us[3],
   157  	}, nil
   158  }
   159  
   160  // btreeStats builds a BTreeStats from a slice of uint32s.
   161  func btreeStats(us []uint32) (BTreeStats, error) {
   162  	if l := len(us); l != 4 {
   163  		return BTreeStats{}, fmt.Errorf("incorrect number of values for XFS btree stats: %d", l)
   164  	}
   165  
   166  	return BTreeStats{
   167  		Lookups:         us[0],
   168  		Compares:        us[1],
   169  		RecordsInserted: us[2],
   170  		RecordsDeleted:  us[3],
   171  	}, nil
   172  }
   173  
   174  // BlockMappingStat builds a BlockMappingStats from a slice of uint32s.
   175  func blockMappingStats(us []uint32) (BlockMappingStats, error) {
   176  	if l := len(us); l != 7 {
   177  		return BlockMappingStats{}, fmt.Errorf("incorrect number of values for XFS block mapping stats: %d", l)
   178  	}
   179  
   180  	return BlockMappingStats{
   181  		Reads:                us[0],
   182  		Writes:               us[1],
   183  		Unmaps:               us[2],
   184  		ExtentListInsertions: us[3],
   185  		ExtentListDeletions:  us[4],
   186  		ExtentListLookups:    us[5],
   187  		ExtentListCompares:   us[6],
   188  	}, nil
   189  }
   190  
   191  // DirectoryOperationStats builds a DirectoryOperationStats from a slice of uint32s.
   192  func directoryOperationStats(us []uint32) (DirectoryOperationStats, error) {
   193  	if l := len(us); l != 4 {
   194  		return DirectoryOperationStats{}, fmt.Errorf("incorrect number of values for XFS directory operation stats: %d", l)
   195  	}
   196  
   197  	return DirectoryOperationStats{
   198  		Lookups:  us[0],
   199  		Creates:  us[1],
   200  		Removes:  us[2],
   201  		Getdents: us[3],
   202  	}, nil
   203  }
   204  
   205  // TransactionStats builds a TransactionStats from a slice of uint32s.
   206  func transactionStats(us []uint32) (TransactionStats, error) {
   207  	if l := len(us); l != 3 {
   208  		return TransactionStats{}, fmt.Errorf("incorrect number of values for XFS transaction stats: %d", l)
   209  	}
   210  
   211  	return TransactionStats{
   212  		Sync:  us[0],
   213  		Async: us[1],
   214  		Empty: us[2],
   215  	}, nil
   216  }
   217  
   218  // InodeOperationStats builds an InodeOperationStats from a slice of uint32s.
   219  func inodeOperationStats(us []uint32) (InodeOperationStats, error) {
   220  	if l := len(us); l != 7 {
   221  		return InodeOperationStats{}, fmt.Errorf("incorrect number of values for XFS inode operation stats: %d", l)
   222  	}
   223  
   224  	return InodeOperationStats{
   225  		Attempts:        us[0],
   226  		Found:           us[1],
   227  		Recycle:         us[2],
   228  		Missed:          us[3],
   229  		Duplicate:       us[4],
   230  		Reclaims:        us[5],
   231  		AttributeChange: us[6],
   232  	}, nil
   233  }
   234  
   235  // LogOperationStats builds a LogOperationStats from a slice of uint32s.
   236  func logOperationStats(us []uint32) (LogOperationStats, error) {
   237  	if l := len(us); l != 5 {
   238  		return LogOperationStats{}, fmt.Errorf("incorrect number of values for XFS log operation stats: %d", l)
   239  	}
   240  
   241  	return LogOperationStats{
   242  		Writes:            us[0],
   243  		Blocks:            us[1],
   244  		NoInternalBuffers: us[2],
   245  		Force:             us[3],
   246  		ForceSleep:        us[4],
   247  	}, nil
   248  }
   249  
   250  // pushAilStats handles push_ail stats.
   251  func pushAilStats(us []uint32) (PushAilStats, error) {
   252  	if l := len(us); l != 10 {
   253  		return PushAilStats{}, fmt.Errorf("incorrect number of values for XFS push ail stats: %d", l)
   254  	}
   255  
   256  	return PushAilStats{
   257  		TryLogspace:   us[0],
   258  		SleepLogspace: us[1],
   259  		Pushes:        us[2],
   260  		Success:       us[3],
   261  		PushBuf:       us[4],
   262  		Pinned:        us[5],
   263  		Locked:        us[6],
   264  		Flushing:      us[7],
   265  		Restarts:      us[8],
   266  		Flush:         us[9],
   267  	}, nil
   268  }
   269  
   270  // xStratStats handles xstrat stats.
   271  func xStratStats(us []uint32) (XstratStats, error) {
   272  	if l := len(us); l != 2 {
   273  		return XstratStats{}, fmt.Errorf("incorrect number of values for XFS  xstrat stats: %d", l)
   274  	}
   275  
   276  	return XstratStats{
   277  		Quick: us[0],
   278  		Split: us[1],
   279  	}, nil
   280  }
   281  
   282  // readWriteStats handles rw stats.
   283  func readWriteStats(us []uint32) (ReadWriteStats, error) {
   284  	if l := len(us); l != 2 {
   285  		return ReadWriteStats{}, fmt.Errorf("incorrect number of values for XFS read write stats: %d", l)
   286  	}
   287  
   288  	return ReadWriteStats{
   289  		Write: us[0],
   290  		Read:  us[1],
   291  	}, nil
   292  }
   293  
   294  // AttributeOperationStats builds an AttributeOperationStats from a slice of uint32s.
   295  func attributeOperationStats(us []uint32) (AttributeOperationStats, error) {
   296  	if l := len(us); l != 4 {
   297  		return AttributeOperationStats{}, fmt.Errorf("incorrect number of values for XFS attribute operation stats: %d", l)
   298  	}
   299  
   300  	return AttributeOperationStats{
   301  		Get:    us[0],
   302  		Set:    us[1],
   303  		Remove: us[2],
   304  		List:   us[3],
   305  	}, nil
   306  }
   307  
   308  // InodeClusteringStats builds an InodeClusteringStats from a slice of uint32s.
   309  func inodeClusteringStats(us []uint32) (InodeClusteringStats, error) {
   310  	if l := len(us); l != 3 {
   311  		return InodeClusteringStats{}, fmt.Errorf("incorrect number of values for XFS inode clustering stats: %d", l)
   312  	}
   313  
   314  	return InodeClusteringStats{
   315  		Iflush:     us[0],
   316  		Flush:      us[1],
   317  		FlushInode: us[2],
   318  	}, nil
   319  }
   320  
   321  // VnodeStats builds a VnodeStats from a slice of uint32s.
   322  func vnodeStats(us []uint32) (VnodeStats, error) {
   323  	// The attribute "Free" appears to not be available on older XFS
   324  	// stats versions.  Therefore, 7 or 8 elements may appear in
   325  	// this slice.
   326  	l := len(us)
   327  	if l != 7 && l != 8 {
   328  		return VnodeStats{}, fmt.Errorf("incorrect number of values for XFS vnode stats: %d", l)
   329  	}
   330  
   331  	s := VnodeStats{
   332  		Active:   us[0],
   333  		Allocate: us[1],
   334  		Get:      us[2],
   335  		Hold:     us[3],
   336  		Release:  us[4],
   337  		Reclaim:  us[5],
   338  		Remove:   us[6],
   339  	}
   340  
   341  	// Skip adding free, unless it is present. The zero value will
   342  	// be used in place of an actual count.
   343  	if l == 7 {
   344  		return s, nil
   345  	}
   346  
   347  	s.Free = us[7]
   348  	return s, nil
   349  }
   350  
   351  // BufferStats builds a BufferStats from a slice of uint32s.
   352  func bufferStats(us []uint32) (BufferStats, error) {
   353  	if l := len(us); l != 9 {
   354  		return BufferStats{}, fmt.Errorf("incorrect number of values for XFS buffer stats: %d", l)
   355  	}
   356  
   357  	return BufferStats{
   358  		Get:             us[0],
   359  		Create:          us[1],
   360  		GetLocked:       us[2],
   361  		GetLockedWaited: us[3],
   362  		BusyLocked:      us[4],
   363  		MissLocked:      us[5],
   364  		PageRetries:     us[6],
   365  		PageFound:       us[7],
   366  		GetRead:         us[8],
   367  	}, nil
   368  }
   369  
   370  // ExtendedPrecisionStats builds an ExtendedPrecisionStats from a slice of uint32s.
   371  func extendedPrecisionStats(us []uint64) (ExtendedPrecisionStats, error) {
   372  	if l := len(us); l != 3 {
   373  		return ExtendedPrecisionStats{}, fmt.Errorf("incorrect number of values for XFS extended precision stats: %d", l)
   374  	}
   375  
   376  	return ExtendedPrecisionStats{
   377  		FlushBytes: us[0],
   378  		WriteBytes: us[1],
   379  		ReadBytes:  us[2],
   380  	}, nil
   381  }
   382  
   383  func quotaManagerStats(us []uint32) (QuotaManagerStats, error) {
   384  	// The "Unused" attribute first appears in Linux 4.20
   385  	// As a result either 8 or 9 elements may appear in this slice depending on
   386  	// the kernel version.
   387  	l := len(us)
   388  	if l != 8 && l != 9 {
   389  		return QuotaManagerStats{}, fmt.Errorf("incorrect number of values for XFS quota stats: %d", l)
   390  	}
   391  
   392  	s := QuotaManagerStats{
   393  		Reclaims:      us[0],
   394  		ReclaimMisses: us[1],
   395  		DquoteDups:    us[2],
   396  		CacheMisses:   us[3],
   397  		CacheHits:     us[4],
   398  		Wants:         us[5],
   399  		ShakeReclaims: us[6],
   400  		InactReclaims: us[7],
   401  	}
   402  
   403  	if l > 8 {
   404  		s.Unused = us[8]
   405  	}
   406  
   407  	return s, nil
   408  }
   409  
   410  func debugStats(us []uint32) (DebugStats, error) {
   411  	if l := len(us); l != 1 {
   412  		return DebugStats{}, fmt.Errorf("incorrect number of values for XFS debug stats: %d", l)
   413  	}
   414  
   415  	return DebugStats{
   416  		Enabled: us[0],
   417  	}, nil
   418  }
   419  
   420  // btreeAllocBlocks2Stats handles abtb2 stats.
   421  func btreeAllocBlocks2Stats(us []uint32) (BtreeAllocBlocks2Stats, error) {
   422  	if l := len(us); l != 15 {
   423  		return BtreeAllocBlocks2Stats{}, fmt.Errorf("incorrect number of values for abtb2 stats: %d", 1)
   424  	}
   425  
   426  	return BtreeAllocBlocks2Stats{
   427  		Lookup:    us[0],
   428  		Compare:   us[1],
   429  		Insrec:    us[2],
   430  		Delrec:    us[3],
   431  		NewRoot:   us[4],
   432  		KillRoot:  us[5],
   433  		Increment: us[6],
   434  		Decrement: us[7],
   435  		Lshift:    us[8],
   436  		Rshift:    us[9],
   437  		Split:     us[10],
   438  		Join:      us[11],
   439  		Alloc:     us[12],
   440  		Free:      us[13],
   441  		Moves:     us[14],
   442  	}, nil
   443  }
   444  
   445  // btreeAllocContig2Stats handles abtc2 stats.
   446  func btreeAllocContig2Stats(us []uint32) (BtreeAllocContig2Stats, error) {
   447  	if l := len(us); l != 15 {
   448  		return BtreeAllocContig2Stats{}, fmt.Errorf("incorrect number of values for abtc2 stats: %d", 1)
   449  	}
   450  
   451  	return BtreeAllocContig2Stats{
   452  		Lookup:    us[0],
   453  		Compare:   us[1],
   454  		Insrec:    us[2],
   455  		Delrec:    us[3],
   456  		NewRoot:   us[4],
   457  		KillRoot:  us[5],
   458  		Increment: us[6],
   459  		Decrement: us[7],
   460  		Lshift:    us[8],
   461  		Rshift:    us[9],
   462  		Split:     us[10],
   463  		Join:      us[11],
   464  		Alloc:     us[12],
   465  		Free:      us[13],
   466  		Moves:     us[14],
   467  	}, nil
   468  }
   469  
   470  // btreeBlockMap2Stats handles bmbt2 stats.
   471  func btreeBlockMap2Stats(us []uint32) (BtreeBlockMap2Stats, error) {
   472  	if l := len(us); l != 15 {
   473  		return BtreeBlockMap2Stats{}, fmt.Errorf("incorrect number of values for bmbt2 stats: %d", 1)
   474  	}
   475  
   476  	return BtreeBlockMap2Stats{
   477  		Lookup:    us[0],
   478  		Compare:   us[1],
   479  		Insrec:    us[2],
   480  		Delrec:    us[3],
   481  		NewRoot:   us[4],
   482  		KillRoot:  us[5],
   483  		Increment: us[6],
   484  		Decrement: us[7],
   485  		Lshift:    us[8],
   486  		Rshift:    us[9],
   487  		Split:     us[10],
   488  		Join:      us[11],
   489  		Alloc:     us[12],
   490  		Free:      us[13],
   491  		Moves:     us[14],
   492  	}, nil
   493  }
   494  
   495  // btreeInode2Stats handles ibt2 stats.
   496  func btreeInode2Stats(us []uint32) (BtreeInode2Stats, error) {
   497  	if l := len(us); l != 15 {
   498  		return BtreeInode2Stats{}, fmt.Errorf("incorrect number of values for ibt2 stats: %d", 1)
   499  	}
   500  
   501  	return BtreeInode2Stats{
   502  		Lookup:    us[0],
   503  		Compare:   us[1],
   504  		Insrec:    us[2],
   505  		Delrec:    us[3],
   506  		NewRoot:   us[4],
   507  		KillRoot:  us[5],
   508  		Increment: us[6],
   509  		Decrement: us[7],
   510  		Lshift:    us[8],
   511  		Rshift:    us[9],
   512  		Split:     us[10],
   513  		Join:      us[11],
   514  		Alloc:     us[12],
   515  		Free:      us[13],
   516  		Moves:     us[14],
   517  	}, nil
   518  }
   519  

View as plain text