423 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			423 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Go
		
	
	
	
| // Copyright 2019 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 procfs
 | |
| 
 | |
| import (
 | |
| 	"bufio"
 | |
| 	"bytes"
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"strconv"
 | |
| 	"strings"
 | |
| 
 | |
| 	"github.com/prometheus/procfs/internal/util"
 | |
| )
 | |
| 
 | |
| // Fscacheinfo represents fscache statistics.
 | |
| type Fscacheinfo struct {
 | |
| 	// Number of index cookies allocated
 | |
| 	IndexCookiesAllocated uint64
 | |
| 	// data storage cookies allocated
 | |
| 	DataStorageCookiesAllocated uint64
 | |
| 	// Number of special cookies allocated
 | |
| 	SpecialCookiesAllocated uint64
 | |
| 	// Number of objects allocated
 | |
| 	ObjectsAllocated uint64
 | |
| 	// Number of object allocation failures
 | |
| 	ObjectAllocationsFailure uint64
 | |
| 	// Number of objects that reached the available state
 | |
| 	ObjectsAvailable uint64
 | |
| 	// Number of objects that reached the dead state
 | |
| 	ObjectsDead uint64
 | |
| 	// Number of objects that didn't have a coherency check
 | |
| 	ObjectsWithoutCoherencyCheck uint64
 | |
| 	// Number of objects that passed a coherency check
 | |
| 	ObjectsWithCoherencyCheck uint64
 | |
| 	// Number of objects that needed a coherency data update
 | |
| 	ObjectsNeedCoherencyCheckUpdate uint64
 | |
| 	// Number of objects that were declared obsolete
 | |
| 	ObjectsDeclaredObsolete uint64
 | |
| 	// Number of pages marked as being cached
 | |
| 	PagesMarkedAsBeingCached uint64
 | |
| 	// Number of uncache page requests seen
 | |
| 	UncachePagesRequestSeen uint64
 | |
| 	// Number of acquire cookie requests seen
 | |
| 	AcquireCookiesRequestSeen uint64
 | |
| 	// Number of acq reqs given a NULL parent
 | |
| 	AcquireRequestsWithNullParent uint64
 | |
| 	// Number of acq reqs rejected due to no cache available
 | |
| 	AcquireRequestsRejectedNoCacheAvailable uint64
 | |
| 	// Number of acq reqs succeeded
 | |
| 	AcquireRequestsSucceeded uint64
 | |
| 	// Number of acq reqs rejected due to error
 | |
| 	AcquireRequestsRejectedDueToError uint64
 | |
| 	// Number of acq reqs failed on ENOMEM
 | |
| 	AcquireRequestsFailedDueToEnomem uint64
 | |
| 	// Number of lookup calls made on cache backends
 | |
| 	LookupsNumber uint64
 | |
| 	// Number of negative lookups made
 | |
| 	LookupsNegative uint64
 | |
| 	// Number of positive lookups made
 | |
| 	LookupsPositive uint64
 | |
| 	// Number of objects created by lookup
 | |
| 	ObjectsCreatedByLookup uint64
 | |
| 	// Number of lookups timed out and requeued
 | |
| 	LookupsTimedOutAndRequed uint64
 | |
| 	InvalidationsNumber      uint64
 | |
| 	InvalidationsRunning     uint64
 | |
| 	// Number of update cookie requests seen
 | |
| 	UpdateCookieRequestSeen uint64
 | |
| 	// Number of upd reqs given a NULL parent
 | |
| 	UpdateRequestsWithNullParent uint64
 | |
| 	// Number of upd reqs granted CPU time
 | |
| 	UpdateRequestsRunning uint64
 | |
| 	// Number of relinquish cookie requests seen
 | |
| 	RelinquishCookiesRequestSeen uint64
 | |
| 	// Number of rlq reqs given a NULL parent
 | |
| 	RelinquishCookiesWithNullParent uint64
 | |
| 	// Number of rlq reqs waited on completion of creation
 | |
| 	RelinquishRequestsWaitingCompleteCreation uint64
 | |
| 	// Relinqs rtr
 | |
| 	RelinquishRetries uint64
 | |
| 	// Number of attribute changed requests seen
 | |
| 	AttributeChangedRequestsSeen uint64
 | |
| 	// Number of attr changed requests queued
 | |
| 	AttributeChangedRequestsQueued uint64
 | |
| 	// Number of attr changed rejected -ENOBUFS
 | |
| 	AttributeChangedRejectDueToEnobufs uint64
 | |
| 	// Number of attr changed failed -ENOMEM
 | |
| 	AttributeChangedFailedDueToEnomem uint64
 | |
| 	// Number of attr changed ops given CPU time
 | |
| 	AttributeChangedOps uint64
 | |
| 	// Number of allocation requests seen
 | |
| 	AllocationRequestsSeen uint64
 | |
| 	// Number of successful alloc reqs
 | |
| 	AllocationOkRequests uint64
 | |
| 	// Number of alloc reqs that waited on lookup completion
 | |
| 	AllocationWaitingOnLookup uint64
 | |
| 	// Number of alloc reqs rejected -ENOBUFS
 | |
| 	AllocationsRejectedDueToEnobufs uint64
 | |
| 	// Number of alloc reqs aborted -ERESTARTSYS
 | |
| 	AllocationsAbortedDueToErestartsys uint64
 | |
| 	// Number of alloc reqs submitted
 | |
| 	AllocationOperationsSubmitted uint64
 | |
| 	// Number of alloc reqs waited for CPU time
 | |
| 	AllocationsWaitedForCPU uint64
 | |
| 	// Number of alloc reqs aborted due to object death
 | |
| 	AllocationsAbortedDueToObjectDeath uint64
 | |
| 	// Number of retrieval (read) requests seen
 | |
| 	RetrievalsReadRequests uint64
 | |
| 	// Number of successful retr reqs
 | |
| 	RetrievalsOk uint64
 | |
| 	// Number of retr reqs that waited on lookup completion
 | |
| 	RetrievalsWaitingLookupCompletion uint64
 | |
| 	// Number of retr reqs returned -ENODATA
 | |
| 	RetrievalsReturnedEnodata uint64
 | |
| 	// Number of retr reqs rejected -ENOBUFS
 | |
| 	RetrievalsRejectedDueToEnobufs uint64
 | |
| 	// Number of retr reqs aborted -ERESTARTSYS
 | |
| 	RetrievalsAbortedDueToErestartsys uint64
 | |
| 	// Number of retr reqs failed -ENOMEM
 | |
| 	RetrievalsFailedDueToEnomem uint64
 | |
| 	// Number of retr reqs submitted
 | |
| 	RetrievalsRequests uint64
 | |
| 	// Number of retr reqs waited for CPU time
 | |
| 	RetrievalsWaitingCPU uint64
 | |
| 	// Number of retr reqs aborted due to object death
 | |
| 	RetrievalsAbortedDueToObjectDeath uint64
 | |
| 	// Number of storage (write) requests seen
 | |
| 	StoreWriteRequests uint64
 | |
| 	// Number of successful store reqs
 | |
| 	StoreSuccessfulRequests uint64
 | |
| 	// Number of store reqs on a page already pending storage
 | |
| 	StoreRequestsOnPendingStorage uint64
 | |
| 	// Number of store reqs rejected -ENOBUFS
 | |
| 	StoreRequestsRejectedDueToEnobufs uint64
 | |
| 	// Number of store reqs failed -ENOMEM
 | |
| 	StoreRequestsFailedDueToEnomem uint64
 | |
| 	// Number of store reqs submitted
 | |
| 	StoreRequestsSubmitted uint64
 | |
| 	// Number of store reqs granted CPU time
 | |
| 	StoreRequestsRunning uint64
 | |
| 	// Number of pages given store req processing time
 | |
| 	StorePagesWithRequestsProcessing uint64
 | |
| 	// Number of store reqs deleted from tracking tree
 | |
| 	StoreRequestsDeleted uint64
 | |
| 	// Number of store reqs over store limit
 | |
| 	StoreRequestsOverStoreLimit uint64
 | |
| 	// Number of release reqs against pages with no pending store
 | |
| 	ReleaseRequestsAgainstPagesWithNoPendingStorage uint64
 | |
| 	// Number of release reqs against pages stored by time lock granted
 | |
| 	ReleaseRequestsAgainstPagesStoredByTimeLockGranted uint64
 | |
| 	// Number of release reqs ignored due to in-progress store
 | |
| 	ReleaseRequestsIgnoredDueToInProgressStore uint64
 | |
| 	// Number of page stores cancelled due to release req
 | |
| 	PageStoresCancelledByReleaseRequests uint64
 | |
| 	VmscanWaiting                        uint64
 | |
| 	// Number of times async ops added to pending queues
 | |
| 	OpsPending uint64
 | |
| 	// Number of times async ops given CPU time
 | |
| 	OpsRunning uint64
 | |
| 	// Number of times async ops queued for processing
 | |
| 	OpsEnqueued uint64
 | |
| 	// Number of async ops cancelled
 | |
| 	OpsCancelled uint64
 | |
| 	// Number of async ops rejected due to object lookup/create failure
 | |
| 	OpsRejected uint64
 | |
| 	// Number of async ops initialised
 | |
| 	OpsInitialised uint64
 | |
| 	// Number of async ops queued for deferred release
 | |
| 	OpsDeferred uint64
 | |
| 	// Number of async ops released (should equal ini=N when idle)
 | |
| 	OpsReleased uint64
 | |
| 	// Number of deferred-release async ops garbage collected
 | |
| 	OpsGarbageCollected uint64
 | |
| 	// Number of in-progress alloc_object() cache ops
 | |
| 	CacheopAllocationsinProgress uint64
 | |
| 	// Number of in-progress lookup_object() cache ops
 | |
| 	CacheopLookupObjectInProgress uint64
 | |
| 	// Number of in-progress lookup_complete() cache ops
 | |
| 	CacheopLookupCompleteInPorgress uint64
 | |
| 	// Number of in-progress grab_object() cache ops
 | |
| 	CacheopGrabObjectInProgress uint64
 | |
| 	CacheopInvalidations        uint64
 | |
| 	// Number of in-progress update_object() cache ops
 | |
| 	CacheopUpdateObjectInProgress uint64
 | |
| 	// Number of in-progress drop_object() cache ops
 | |
| 	CacheopDropObjectInProgress uint64
 | |
| 	// Number of in-progress put_object() cache ops
 | |
| 	CacheopPutObjectInProgress uint64
 | |
| 	// Number of in-progress attr_changed() cache ops
 | |
| 	CacheopAttributeChangeInProgress uint64
 | |
| 	// Number of in-progress sync_cache() cache ops
 | |
| 	CacheopSyncCacheInProgress uint64
 | |
| 	// Number of in-progress read_or_alloc_page() cache ops
 | |
| 	CacheopReadOrAllocPageInProgress uint64
 | |
| 	// Number of in-progress read_or_alloc_pages() cache ops
 | |
| 	CacheopReadOrAllocPagesInProgress uint64
 | |
| 	// Number of in-progress allocate_page() cache ops
 | |
| 	CacheopAllocatePageInProgress uint64
 | |
| 	// Number of in-progress allocate_pages() cache ops
 | |
| 	CacheopAllocatePagesInProgress uint64
 | |
| 	// Number of in-progress write_page() cache ops
 | |
| 	CacheopWritePagesInProgress uint64
 | |
| 	// Number of in-progress uncache_page() cache ops
 | |
| 	CacheopUncachePagesInProgress uint64
 | |
| 	// Number of in-progress dissociate_pages() cache ops
 | |
| 	CacheopDissociatePagesInProgress uint64
 | |
| 	// Number of object lookups/creations rejected due to lack of space
 | |
| 	CacheevLookupsAndCreationsRejectedLackSpace uint64
 | |
| 	// Number of stale objects deleted
 | |
| 	CacheevStaleObjectsDeleted uint64
 | |
| 	// Number of objects retired when relinquished
 | |
| 	CacheevRetiredWhenReliquished uint64
 | |
| 	// Number of objects culled
 | |
| 	CacheevObjectsCulled uint64
 | |
| }
 | |
| 
 | |
| // Fscacheinfo returns information about current fscache statistics.
 | |
| // See https://www.kernel.org/doc/Documentation/filesystems/caching/fscache.txt
 | |
| func (fs FS) Fscacheinfo() (Fscacheinfo, error) {
 | |
| 	b, err := util.ReadFileNoStat(fs.proc.Path("fs/fscache/stats"))
 | |
| 	if err != nil {
 | |
| 		return Fscacheinfo{}, err
 | |
| 	}
 | |
| 
 | |
| 	m, err := parseFscacheinfo(bytes.NewReader(b))
 | |
| 	if err != nil {
 | |
| 		return Fscacheinfo{}, fmt.Errorf("failed to parse Fscacheinfo: %w", err)
 | |
| 	}
 | |
| 
 | |
| 	return *m, nil
 | |
| }
 | |
| 
 | |
| func setFSCacheFields(fields []string, setFields ...*uint64) error {
 | |
| 	var err error
 | |
| 	if len(fields) < len(setFields) {
 | |
| 		return fmt.Errorf("Insufficient number of fields, expected %v, got %v", len(setFields), len(fields))
 | |
| 	}
 | |
| 
 | |
| 	for i := range setFields {
 | |
| 		*setFields[i], err = strconv.ParseUint(strings.Split(fields[i], "=")[1], 0, 64)
 | |
| 		if err != nil {
 | |
| 			return err
 | |
| 		}
 | |
| 	}
 | |
| 	return nil
 | |
| }
 | |
| 
 | |
| func parseFscacheinfo(r io.Reader) (*Fscacheinfo, error) {
 | |
| 	var m Fscacheinfo
 | |
| 	s := bufio.NewScanner(r)
 | |
| 	for s.Scan() {
 | |
| 		fields := strings.Fields(s.Text())
 | |
| 		if len(fields) < 2 {
 | |
| 			return nil, fmt.Errorf("malformed Fscacheinfo line: %q", s.Text())
 | |
| 		}
 | |
| 
 | |
| 		switch fields[0] {
 | |
| 		case "Cookies:":
 | |
| 			err := setFSCacheFields(fields[1:], &m.IndexCookiesAllocated, &m.DataStorageCookiesAllocated,
 | |
| 				&m.SpecialCookiesAllocated)
 | |
| 			if err != nil {
 | |
| 				return &m, err
 | |
| 			}
 | |
| 		case "Objects:":
 | |
| 			err := setFSCacheFields(fields[1:], &m.ObjectsAllocated, &m.ObjectAllocationsFailure,
 | |
| 				&m.ObjectsAvailable, &m.ObjectsDead)
 | |
| 			if err != nil {
 | |
| 				return &m, err
 | |
| 			}
 | |
| 		case "ChkAux":
 | |
| 			err := setFSCacheFields(fields[2:], &m.ObjectsWithoutCoherencyCheck, &m.ObjectsWithCoherencyCheck,
 | |
| 				&m.ObjectsNeedCoherencyCheckUpdate, &m.ObjectsDeclaredObsolete)
 | |
| 			if err != nil {
 | |
| 				return &m, err
 | |
| 			}
 | |
| 		case "Pages":
 | |
| 			err := setFSCacheFields(fields[2:], &m.PagesMarkedAsBeingCached, &m.UncachePagesRequestSeen)
 | |
| 			if err != nil {
 | |
| 				return &m, err
 | |
| 			}
 | |
| 		case "Acquire:":
 | |
| 			err := setFSCacheFields(fields[1:], &m.AcquireCookiesRequestSeen, &m.AcquireRequestsWithNullParent,
 | |
| 				&m.AcquireRequestsRejectedNoCacheAvailable, &m.AcquireRequestsSucceeded, &m.AcquireRequestsRejectedDueToError,
 | |
| 				&m.AcquireRequestsFailedDueToEnomem)
 | |
| 			if err != nil {
 | |
| 				return &m, err
 | |
| 			}
 | |
| 		case "Lookups:":
 | |
| 			err := setFSCacheFields(fields[1:], &m.LookupsNumber, &m.LookupsNegative, &m.LookupsPositive,
 | |
| 				&m.ObjectsCreatedByLookup, &m.LookupsTimedOutAndRequed)
 | |
| 			if err != nil {
 | |
| 				return &m, err
 | |
| 			}
 | |
| 		case "Invals":
 | |
| 			err := setFSCacheFields(fields[2:], &m.InvalidationsNumber, &m.InvalidationsRunning)
 | |
| 			if err != nil {
 | |
| 				return &m, err
 | |
| 			}
 | |
| 		case "Updates:":
 | |
| 			err := setFSCacheFields(fields[1:], &m.UpdateCookieRequestSeen, &m.UpdateRequestsWithNullParent,
 | |
| 				&m.UpdateRequestsRunning)
 | |
| 			if err != nil {
 | |
| 				return &m, err
 | |
| 			}
 | |
| 		case "Relinqs:":
 | |
| 			err := setFSCacheFields(fields[1:], &m.RelinquishCookiesRequestSeen, &m.RelinquishCookiesWithNullParent,
 | |
| 				&m.RelinquishRequestsWaitingCompleteCreation, &m.RelinquishRetries)
 | |
| 			if err != nil {
 | |
| 				return &m, err
 | |
| 			}
 | |
| 		case "AttrChg:":
 | |
| 			err := setFSCacheFields(fields[1:], &m.AttributeChangedRequestsSeen, &m.AttributeChangedRequestsQueued,
 | |
| 				&m.AttributeChangedRejectDueToEnobufs, &m.AttributeChangedFailedDueToEnomem, &m.AttributeChangedOps)
 | |
| 			if err != nil {
 | |
| 				return &m, err
 | |
| 			}
 | |
| 		case "Allocs":
 | |
| 			if strings.Split(fields[2], "=")[0] == "n" {
 | |
| 				err := setFSCacheFields(fields[2:], &m.AllocationRequestsSeen, &m.AllocationOkRequests,
 | |
| 					&m.AllocationWaitingOnLookup, &m.AllocationsRejectedDueToEnobufs, &m.AllocationsAbortedDueToErestartsys)
 | |
| 				if err != nil {
 | |
| 					return &m, err
 | |
| 				}
 | |
| 			} else {
 | |
| 				err := setFSCacheFields(fields[2:], &m.AllocationOperationsSubmitted, &m.AllocationsWaitedForCPU,
 | |
| 					&m.AllocationsAbortedDueToObjectDeath)
 | |
| 				if err != nil {
 | |
| 					return &m, err
 | |
| 				}
 | |
| 			}
 | |
| 		case "Retrvls:":
 | |
| 			if strings.Split(fields[1], "=")[0] == "n" {
 | |
| 				err := setFSCacheFields(fields[1:], &m.RetrievalsReadRequests, &m.RetrievalsOk, &m.RetrievalsWaitingLookupCompletion,
 | |
| 					&m.RetrievalsReturnedEnodata, &m.RetrievalsRejectedDueToEnobufs, &m.RetrievalsAbortedDueToErestartsys,
 | |
| 					&m.RetrievalsFailedDueToEnomem)
 | |
| 				if err != nil {
 | |
| 					return &m, err
 | |
| 				}
 | |
| 			} else {
 | |
| 				err := setFSCacheFields(fields[1:], &m.RetrievalsRequests, &m.RetrievalsWaitingCPU, &m.RetrievalsAbortedDueToObjectDeath)
 | |
| 				if err != nil {
 | |
| 					return &m, err
 | |
| 				}
 | |
| 			}
 | |
| 		case "Stores":
 | |
| 			if strings.Split(fields[2], "=")[0] == "n" {
 | |
| 				err := setFSCacheFields(fields[2:], &m.StoreWriteRequests, &m.StoreSuccessfulRequests,
 | |
| 					&m.StoreRequestsOnPendingStorage, &m.StoreRequestsRejectedDueToEnobufs, &m.StoreRequestsFailedDueToEnomem)
 | |
| 				if err != nil {
 | |
| 					return &m, err
 | |
| 				}
 | |
| 			} else {
 | |
| 				err := setFSCacheFields(fields[2:], &m.StoreRequestsSubmitted, &m.StoreRequestsRunning,
 | |
| 					&m.StorePagesWithRequestsProcessing, &m.StoreRequestsDeleted, &m.StoreRequestsOverStoreLimit)
 | |
| 				if err != nil {
 | |
| 					return &m, err
 | |
| 				}
 | |
| 			}
 | |
| 		case "VmScan":
 | |
| 			err := setFSCacheFields(fields[2:], &m.ReleaseRequestsAgainstPagesWithNoPendingStorage,
 | |
| 				&m.ReleaseRequestsAgainstPagesStoredByTimeLockGranted, &m.ReleaseRequestsIgnoredDueToInProgressStore,
 | |
| 				&m.PageStoresCancelledByReleaseRequests, &m.VmscanWaiting)
 | |
| 			if err != nil {
 | |
| 				return &m, err
 | |
| 			}
 | |
| 		case "Ops":
 | |
| 			if strings.Split(fields[2], "=")[0] == "pend" {
 | |
| 				err := setFSCacheFields(fields[2:], &m.OpsPending, &m.OpsRunning, &m.OpsEnqueued, &m.OpsCancelled, &m.OpsRejected)
 | |
| 				if err != nil {
 | |
| 					return &m, err
 | |
| 				}
 | |
| 			} else {
 | |
| 				err := setFSCacheFields(fields[2:], &m.OpsInitialised, &m.OpsDeferred, &m.OpsReleased, &m.OpsGarbageCollected)
 | |
| 				if err != nil {
 | |
| 					return &m, err
 | |
| 				}
 | |
| 			}
 | |
| 		case "CacheOp:":
 | |
| 			if strings.Split(fields[1], "=")[0] == "alo" {
 | |
| 				err := setFSCacheFields(fields[1:], &m.CacheopAllocationsinProgress, &m.CacheopLookupObjectInProgress,
 | |
| 					&m.CacheopLookupCompleteInPorgress, &m.CacheopGrabObjectInProgress)
 | |
| 				if err != nil {
 | |
| 					return &m, err
 | |
| 				}
 | |
| 			} else if strings.Split(fields[1], "=")[0] == "inv" {
 | |
| 				err := setFSCacheFields(fields[1:], &m.CacheopInvalidations, &m.CacheopUpdateObjectInProgress,
 | |
| 					&m.CacheopDropObjectInProgress, &m.CacheopPutObjectInProgress, &m.CacheopAttributeChangeInProgress,
 | |
| 					&m.CacheopSyncCacheInProgress)
 | |
| 				if err != nil {
 | |
| 					return &m, err
 | |
| 				}
 | |
| 			} else {
 | |
| 				err := setFSCacheFields(fields[1:], &m.CacheopReadOrAllocPageInProgress, &m.CacheopReadOrAllocPagesInProgress,
 | |
| 					&m.CacheopAllocatePageInProgress, &m.CacheopAllocatePagesInProgress, &m.CacheopWritePagesInProgress,
 | |
| 					&m.CacheopUncachePagesInProgress, &m.CacheopDissociatePagesInProgress)
 | |
| 				if err != nil {
 | |
| 					return &m, err
 | |
| 				}
 | |
| 			}
 | |
| 		case "CacheEv:":
 | |
| 			err := setFSCacheFields(fields[1:], &m.CacheevLookupsAndCreationsRejectedLackSpace, &m.CacheevStaleObjectsDeleted,
 | |
| 				&m.CacheevRetiredWhenReliquished, &m.CacheevObjectsCulled)
 | |
| 			if err != nil {
 | |
| 				return &m, err
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return &m, nil
 | |
| }
 |