278 lines
		
	
	
		
			8.0 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			278 lines
		
	
	
		
			8.0 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"
 | 
						|
)
 | 
						|
 | 
						|
// Meminfo represents memory statistics.
 | 
						|
type Meminfo struct {
 | 
						|
	// Total usable ram (i.e. physical ram minus a few reserved
 | 
						|
	// bits and the kernel binary code)
 | 
						|
	MemTotal uint64
 | 
						|
	// The sum of LowFree+HighFree
 | 
						|
	MemFree uint64
 | 
						|
	// An estimate of how much memory is available for starting
 | 
						|
	// new applications, without swapping. Calculated from
 | 
						|
	// MemFree, SReclaimable, the size of the file LRU lists, and
 | 
						|
	// the low watermarks in each zone.  The estimate takes into
 | 
						|
	// account that the system needs some page cache to function
 | 
						|
	// well, and that not all reclaimable slab will be
 | 
						|
	// reclaimable, due to items being in use. The impact of those
 | 
						|
	// factors will vary from system to system.
 | 
						|
	MemAvailable uint64
 | 
						|
	// Relatively temporary storage for raw disk blocks shouldn't
 | 
						|
	// get tremendously large (20MB or so)
 | 
						|
	Buffers uint64
 | 
						|
	Cached  uint64
 | 
						|
	// Memory that once was swapped out, is swapped back in but
 | 
						|
	// still also is in the swapfile (if memory is needed it
 | 
						|
	// doesn't need to be swapped out AGAIN because it is already
 | 
						|
	// in the swapfile. This saves I/O)
 | 
						|
	SwapCached uint64
 | 
						|
	// Memory that has been used more recently and usually not
 | 
						|
	// reclaimed unless absolutely necessary.
 | 
						|
	Active uint64
 | 
						|
	// Memory which has been less recently used.  It is more
 | 
						|
	// eligible to be reclaimed for other purposes
 | 
						|
	Inactive     uint64
 | 
						|
	ActiveAnon   uint64
 | 
						|
	InactiveAnon uint64
 | 
						|
	ActiveFile   uint64
 | 
						|
	InactiveFile uint64
 | 
						|
	Unevictable  uint64
 | 
						|
	Mlocked      uint64
 | 
						|
	// total amount of swap space available
 | 
						|
	SwapTotal uint64
 | 
						|
	// Memory which has been evicted from RAM, and is temporarily
 | 
						|
	// on the disk
 | 
						|
	SwapFree uint64
 | 
						|
	// Memory which is waiting to get written back to the disk
 | 
						|
	Dirty uint64
 | 
						|
	// Memory which is actively being written back to the disk
 | 
						|
	Writeback uint64
 | 
						|
	// Non-file backed pages mapped into userspace page tables
 | 
						|
	AnonPages uint64
 | 
						|
	// files which have been mapped, such as libraries
 | 
						|
	Mapped uint64
 | 
						|
	Shmem  uint64
 | 
						|
	// in-kernel data structures cache
 | 
						|
	Slab uint64
 | 
						|
	// Part of Slab, that might be reclaimed, such as caches
 | 
						|
	SReclaimable uint64
 | 
						|
	// Part of Slab, that cannot be reclaimed on memory pressure
 | 
						|
	SUnreclaim  uint64
 | 
						|
	KernelStack uint64
 | 
						|
	// amount of memory dedicated to the lowest level of page
 | 
						|
	// tables.
 | 
						|
	PageTables uint64
 | 
						|
	// NFS pages sent to the server, but not yet committed to
 | 
						|
	// stable storage
 | 
						|
	NFSUnstable uint64
 | 
						|
	// Memory used for block device "bounce buffers"
 | 
						|
	Bounce uint64
 | 
						|
	// Memory used by FUSE for temporary writeback buffers
 | 
						|
	WritebackTmp uint64
 | 
						|
	// Based on the overcommit ratio ('vm.overcommit_ratio'),
 | 
						|
	// this is the total amount of  memory currently available to
 | 
						|
	// be allocated on the system. This limit is only adhered to
 | 
						|
	// if strict overcommit accounting is enabled (mode 2 in
 | 
						|
	// 'vm.overcommit_memory').
 | 
						|
	// The CommitLimit is calculated with the following formula:
 | 
						|
	// CommitLimit = ([total RAM pages] - [total huge TLB pages]) *
 | 
						|
	//                overcommit_ratio / 100 + [total swap pages]
 | 
						|
	// For example, on a system with 1G of physical RAM and 7G
 | 
						|
	// of swap with a `vm.overcommit_ratio` of 30 it would
 | 
						|
	// yield a CommitLimit of 7.3G.
 | 
						|
	// For more details, see the memory overcommit documentation
 | 
						|
	// in vm/overcommit-accounting.
 | 
						|
	CommitLimit uint64
 | 
						|
	// The amount of memory presently allocated on the system.
 | 
						|
	// The committed memory is a sum of all of the memory which
 | 
						|
	// has been allocated by processes, even if it has not been
 | 
						|
	// "used" by them as of yet. A process which malloc()'s 1G
 | 
						|
	// of memory, but only touches 300M of it will show up as
 | 
						|
	// using 1G. This 1G is memory which has been "committed" to
 | 
						|
	// by the VM and can be used at any time by the allocating
 | 
						|
	// application. With strict overcommit enabled on the system
 | 
						|
	// (mode 2 in 'vm.overcommit_memory'),allocations which would
 | 
						|
	// exceed the CommitLimit (detailed above) will not be permitted.
 | 
						|
	// This is useful if one needs to guarantee that processes will
 | 
						|
	// not fail due to lack of memory once that memory has been
 | 
						|
	// successfully allocated.
 | 
						|
	CommittedAS uint64
 | 
						|
	// total size of vmalloc memory area
 | 
						|
	VmallocTotal uint64
 | 
						|
	// amount of vmalloc area which is used
 | 
						|
	VmallocUsed uint64
 | 
						|
	// largest contiguous block of vmalloc area which is free
 | 
						|
	VmallocChunk      uint64
 | 
						|
	HardwareCorrupted uint64
 | 
						|
	AnonHugePages     uint64
 | 
						|
	ShmemHugePages    uint64
 | 
						|
	ShmemPmdMapped    uint64
 | 
						|
	CmaTotal          uint64
 | 
						|
	CmaFree           uint64
 | 
						|
	HugePagesTotal    uint64
 | 
						|
	HugePagesFree     uint64
 | 
						|
	HugePagesRsvd     uint64
 | 
						|
	HugePagesSurp     uint64
 | 
						|
	Hugepagesize      uint64
 | 
						|
	DirectMap4k       uint64
 | 
						|
	DirectMap2M       uint64
 | 
						|
	DirectMap1G       uint64
 | 
						|
}
 | 
						|
 | 
						|
// Meminfo returns an information about current kernel/system memory statistics.
 | 
						|
// See https://www.kernel.org/doc/Documentation/filesystems/proc.txt
 | 
						|
func (fs FS) Meminfo() (Meminfo, error) {
 | 
						|
	b, err := util.ReadFileNoStat(fs.proc.Path("meminfo"))
 | 
						|
	if err != nil {
 | 
						|
		return Meminfo{}, err
 | 
						|
	}
 | 
						|
 | 
						|
	m, err := parseMemInfo(bytes.NewReader(b))
 | 
						|
	if err != nil {
 | 
						|
		return Meminfo{}, fmt.Errorf("failed to parse meminfo: %v", err)
 | 
						|
	}
 | 
						|
 | 
						|
	return *m, nil
 | 
						|
}
 | 
						|
 | 
						|
func parseMemInfo(r io.Reader) (*Meminfo, error) {
 | 
						|
	var m Meminfo
 | 
						|
	s := bufio.NewScanner(r)
 | 
						|
	for s.Scan() {
 | 
						|
		// Each line has at least a name and value; we ignore the unit.
 | 
						|
		fields := strings.Fields(s.Text())
 | 
						|
		if len(fields) < 2 {
 | 
						|
			return nil, fmt.Errorf("malformed meminfo line: %q", s.Text())
 | 
						|
		}
 | 
						|
 | 
						|
		v, err := strconv.ParseUint(fields[1], 0, 64)
 | 
						|
		if err != nil {
 | 
						|
			return nil, err
 | 
						|
		}
 | 
						|
 | 
						|
		switch fields[0] {
 | 
						|
		case "MemTotal:":
 | 
						|
			m.MemTotal = v
 | 
						|
		case "MemFree:":
 | 
						|
			m.MemFree = v
 | 
						|
		case "MemAvailable:":
 | 
						|
			m.MemAvailable = v
 | 
						|
		case "Buffers:":
 | 
						|
			m.Buffers = v
 | 
						|
		case "Cached:":
 | 
						|
			m.Cached = v
 | 
						|
		case "SwapCached:":
 | 
						|
			m.SwapCached = v
 | 
						|
		case "Active:":
 | 
						|
			m.Active = v
 | 
						|
		case "Inactive:":
 | 
						|
			m.Inactive = v
 | 
						|
		case "Active(anon):":
 | 
						|
			m.ActiveAnon = v
 | 
						|
		case "Inactive(anon):":
 | 
						|
			m.InactiveAnon = v
 | 
						|
		case "Active(file):":
 | 
						|
			m.ActiveFile = v
 | 
						|
		case "Inactive(file):":
 | 
						|
			m.InactiveFile = v
 | 
						|
		case "Unevictable:":
 | 
						|
			m.Unevictable = v
 | 
						|
		case "Mlocked:":
 | 
						|
			m.Mlocked = v
 | 
						|
		case "SwapTotal:":
 | 
						|
			m.SwapTotal = v
 | 
						|
		case "SwapFree:":
 | 
						|
			m.SwapFree = v
 | 
						|
		case "Dirty:":
 | 
						|
			m.Dirty = v
 | 
						|
		case "Writeback:":
 | 
						|
			m.Writeback = v
 | 
						|
		case "AnonPages:":
 | 
						|
			m.AnonPages = v
 | 
						|
		case "Mapped:":
 | 
						|
			m.Mapped = v
 | 
						|
		case "Shmem:":
 | 
						|
			m.Shmem = v
 | 
						|
		case "Slab:":
 | 
						|
			m.Slab = v
 | 
						|
		case "SReclaimable:":
 | 
						|
			m.SReclaimable = v
 | 
						|
		case "SUnreclaim:":
 | 
						|
			m.SUnreclaim = v
 | 
						|
		case "KernelStack:":
 | 
						|
			m.KernelStack = v
 | 
						|
		case "PageTables:":
 | 
						|
			m.PageTables = v
 | 
						|
		case "NFS_Unstable:":
 | 
						|
			m.NFSUnstable = v
 | 
						|
		case "Bounce:":
 | 
						|
			m.Bounce = v
 | 
						|
		case "WritebackTmp:":
 | 
						|
			m.WritebackTmp = v
 | 
						|
		case "CommitLimit:":
 | 
						|
			m.CommitLimit = v
 | 
						|
		case "Committed_AS:":
 | 
						|
			m.CommittedAS = v
 | 
						|
		case "VmallocTotal:":
 | 
						|
			m.VmallocTotal = v
 | 
						|
		case "VmallocUsed:":
 | 
						|
			m.VmallocUsed = v
 | 
						|
		case "VmallocChunk:":
 | 
						|
			m.VmallocChunk = v
 | 
						|
		case "HardwareCorrupted:":
 | 
						|
			m.HardwareCorrupted = v
 | 
						|
		case "AnonHugePages:":
 | 
						|
			m.AnonHugePages = v
 | 
						|
		case "ShmemHugePages:":
 | 
						|
			m.ShmemHugePages = v
 | 
						|
		case "ShmemPmdMapped:":
 | 
						|
			m.ShmemPmdMapped = v
 | 
						|
		case "CmaTotal:":
 | 
						|
			m.CmaTotal = v
 | 
						|
		case "CmaFree:":
 | 
						|
			m.CmaFree = v
 | 
						|
		case "HugePages_Total:":
 | 
						|
			m.HugePagesTotal = v
 | 
						|
		case "HugePages_Free:":
 | 
						|
			m.HugePagesFree = v
 | 
						|
		case "HugePages_Rsvd:":
 | 
						|
			m.HugePagesRsvd = v
 | 
						|
		case "HugePages_Surp:":
 | 
						|
			m.HugePagesSurp = v
 | 
						|
		case "Hugepagesize:":
 | 
						|
			m.Hugepagesize = v
 | 
						|
		case "DirectMap4k:":
 | 
						|
			m.DirectMap4k = v
 | 
						|
		case "DirectMap2M:":
 | 
						|
			m.DirectMap2M = v
 | 
						|
		case "DirectMap1G:":
 | 
						|
			m.DirectMap1G = v
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return &m, nil
 | 
						|
}
 |