mirror of
				https://github.com/superseriousbusiness/gotosocial.git
				synced 2025-10-31 04:02:26 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			389 lines
		
	
	
	
		
			12 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			389 lines
		
	
	
	
		
			12 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
 | |
| 	Percpu            *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
 | |
| 
 | |
| 	// The struct fields below are the byte-normalized counterparts to the
 | |
| 	// existing struct fields. Values are normalized using the optional
 | |
| 	// unit field in the meminfo line.
 | |
| 	MemTotalBytes          *uint64
 | |
| 	MemFreeBytes           *uint64
 | |
| 	MemAvailableBytes      *uint64
 | |
| 	BuffersBytes           *uint64
 | |
| 	CachedBytes            *uint64
 | |
| 	SwapCachedBytes        *uint64
 | |
| 	ActiveBytes            *uint64
 | |
| 	InactiveBytes          *uint64
 | |
| 	ActiveAnonBytes        *uint64
 | |
| 	InactiveAnonBytes      *uint64
 | |
| 	ActiveFileBytes        *uint64
 | |
| 	InactiveFileBytes      *uint64
 | |
| 	UnevictableBytes       *uint64
 | |
| 	MlockedBytes           *uint64
 | |
| 	SwapTotalBytes         *uint64
 | |
| 	SwapFreeBytes          *uint64
 | |
| 	DirtyBytes             *uint64
 | |
| 	WritebackBytes         *uint64
 | |
| 	AnonPagesBytes         *uint64
 | |
| 	MappedBytes            *uint64
 | |
| 	ShmemBytes             *uint64
 | |
| 	SlabBytes              *uint64
 | |
| 	SReclaimableBytes      *uint64
 | |
| 	SUnreclaimBytes        *uint64
 | |
| 	KernelStackBytes       *uint64
 | |
| 	PageTablesBytes        *uint64
 | |
| 	NFSUnstableBytes       *uint64
 | |
| 	BounceBytes            *uint64
 | |
| 	WritebackTmpBytes      *uint64
 | |
| 	CommitLimitBytes       *uint64
 | |
| 	CommittedASBytes       *uint64
 | |
| 	VmallocTotalBytes      *uint64
 | |
| 	VmallocUsedBytes       *uint64
 | |
| 	VmallocChunkBytes      *uint64
 | |
| 	PercpuBytes            *uint64
 | |
| 	HardwareCorruptedBytes *uint64
 | |
| 	AnonHugePagesBytes     *uint64
 | |
| 	ShmemHugePagesBytes    *uint64
 | |
| 	ShmemPmdMappedBytes    *uint64
 | |
| 	CmaTotalBytes          *uint64
 | |
| 	CmaFreeBytes           *uint64
 | |
| 	HugepagesizeBytes      *uint64
 | |
| 	DirectMap4kBytes       *uint64
 | |
| 	DirectMap2MBytes       *uint64
 | |
| 	DirectMap1GBytes       *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("%w: %w", ErrFileParse, err)
 | |
| 	}
 | |
| 
 | |
| 	return *m, nil
 | |
| }
 | |
| 
 | |
| func parseMemInfo(r io.Reader) (*Meminfo, error) {
 | |
| 	var m Meminfo
 | |
| 	s := bufio.NewScanner(r)
 | |
| 	for s.Scan() {
 | |
| 		fields := strings.Fields(s.Text())
 | |
| 		var val, valBytes uint64
 | |
| 
 | |
| 		val, err := strconv.ParseUint(fields[1], 0, 64)
 | |
| 		if err != nil {
 | |
| 			return nil, err
 | |
| 		}
 | |
| 
 | |
| 		switch len(fields) {
 | |
| 		case 2:
 | |
| 			// No unit present, use the parsed the value as bytes directly.
 | |
| 			valBytes = val
 | |
| 		case 3:
 | |
| 			// Unit present in optional 3rd field, convert it to
 | |
| 			// bytes. The only unit supported within the Linux
 | |
| 			// kernel is `kB`.
 | |
| 			if fields[2] != "kB" {
 | |
| 				return nil, fmt.Errorf("%w: Unsupported unit in optional 3rd field %q", ErrFileParse, fields[2])
 | |
| 			}
 | |
| 
 | |
| 			valBytes = 1024 * val
 | |
| 
 | |
| 		default:
 | |
| 			return nil, fmt.Errorf("%w: Malformed line %q", ErrFileParse, s.Text())
 | |
| 		}
 | |
| 
 | |
| 		switch fields[0] {
 | |
| 		case "MemTotal:":
 | |
| 			m.MemTotal = &val
 | |
| 			m.MemTotalBytes = &valBytes
 | |
| 		case "MemFree:":
 | |
| 			m.MemFree = &val
 | |
| 			m.MemFreeBytes = &valBytes
 | |
| 		case "MemAvailable:":
 | |
| 			m.MemAvailable = &val
 | |
| 			m.MemAvailableBytes = &valBytes
 | |
| 		case "Buffers:":
 | |
| 			m.Buffers = &val
 | |
| 			m.BuffersBytes = &valBytes
 | |
| 		case "Cached:":
 | |
| 			m.Cached = &val
 | |
| 			m.CachedBytes = &valBytes
 | |
| 		case "SwapCached:":
 | |
| 			m.SwapCached = &val
 | |
| 			m.SwapCachedBytes = &valBytes
 | |
| 		case "Active:":
 | |
| 			m.Active = &val
 | |
| 			m.ActiveBytes = &valBytes
 | |
| 		case "Inactive:":
 | |
| 			m.Inactive = &val
 | |
| 			m.InactiveBytes = &valBytes
 | |
| 		case "Active(anon):":
 | |
| 			m.ActiveAnon = &val
 | |
| 			m.ActiveAnonBytes = &valBytes
 | |
| 		case "Inactive(anon):":
 | |
| 			m.InactiveAnon = &val
 | |
| 			m.InactiveAnonBytes = &valBytes
 | |
| 		case "Active(file):":
 | |
| 			m.ActiveFile = &val
 | |
| 			m.ActiveFileBytes = &valBytes
 | |
| 		case "Inactive(file):":
 | |
| 			m.InactiveFile = &val
 | |
| 			m.InactiveFileBytes = &valBytes
 | |
| 		case "Unevictable:":
 | |
| 			m.Unevictable = &val
 | |
| 			m.UnevictableBytes = &valBytes
 | |
| 		case "Mlocked:":
 | |
| 			m.Mlocked = &val
 | |
| 			m.MlockedBytes = &valBytes
 | |
| 		case "SwapTotal:":
 | |
| 			m.SwapTotal = &val
 | |
| 			m.SwapTotalBytes = &valBytes
 | |
| 		case "SwapFree:":
 | |
| 			m.SwapFree = &val
 | |
| 			m.SwapFreeBytes = &valBytes
 | |
| 		case "Dirty:":
 | |
| 			m.Dirty = &val
 | |
| 			m.DirtyBytes = &valBytes
 | |
| 		case "Writeback:":
 | |
| 			m.Writeback = &val
 | |
| 			m.WritebackBytes = &valBytes
 | |
| 		case "AnonPages:":
 | |
| 			m.AnonPages = &val
 | |
| 			m.AnonPagesBytes = &valBytes
 | |
| 		case "Mapped:":
 | |
| 			m.Mapped = &val
 | |
| 			m.MappedBytes = &valBytes
 | |
| 		case "Shmem:":
 | |
| 			m.Shmem = &val
 | |
| 			m.ShmemBytes = &valBytes
 | |
| 		case "Slab:":
 | |
| 			m.Slab = &val
 | |
| 			m.SlabBytes = &valBytes
 | |
| 		case "SReclaimable:":
 | |
| 			m.SReclaimable = &val
 | |
| 			m.SReclaimableBytes = &valBytes
 | |
| 		case "SUnreclaim:":
 | |
| 			m.SUnreclaim = &val
 | |
| 			m.SUnreclaimBytes = &valBytes
 | |
| 		case "KernelStack:":
 | |
| 			m.KernelStack = &val
 | |
| 			m.KernelStackBytes = &valBytes
 | |
| 		case "PageTables:":
 | |
| 			m.PageTables = &val
 | |
| 			m.PageTablesBytes = &valBytes
 | |
| 		case "NFS_Unstable:":
 | |
| 			m.NFSUnstable = &val
 | |
| 			m.NFSUnstableBytes = &valBytes
 | |
| 		case "Bounce:":
 | |
| 			m.Bounce = &val
 | |
| 			m.BounceBytes = &valBytes
 | |
| 		case "WritebackTmp:":
 | |
| 			m.WritebackTmp = &val
 | |
| 			m.WritebackTmpBytes = &valBytes
 | |
| 		case "CommitLimit:":
 | |
| 			m.CommitLimit = &val
 | |
| 			m.CommitLimitBytes = &valBytes
 | |
| 		case "Committed_AS:":
 | |
| 			m.CommittedAS = &val
 | |
| 			m.CommittedASBytes = &valBytes
 | |
| 		case "VmallocTotal:":
 | |
| 			m.VmallocTotal = &val
 | |
| 			m.VmallocTotalBytes = &valBytes
 | |
| 		case "VmallocUsed:":
 | |
| 			m.VmallocUsed = &val
 | |
| 			m.VmallocUsedBytes = &valBytes
 | |
| 		case "VmallocChunk:":
 | |
| 			m.VmallocChunk = &val
 | |
| 			m.VmallocChunkBytes = &valBytes
 | |
| 		case "Percpu:":
 | |
| 			m.Percpu = &val
 | |
| 			m.PercpuBytes = &valBytes
 | |
| 		case "HardwareCorrupted:":
 | |
| 			m.HardwareCorrupted = &val
 | |
| 			m.HardwareCorruptedBytes = &valBytes
 | |
| 		case "AnonHugePages:":
 | |
| 			m.AnonHugePages = &val
 | |
| 			m.AnonHugePagesBytes = &valBytes
 | |
| 		case "ShmemHugePages:":
 | |
| 			m.ShmemHugePages = &val
 | |
| 			m.ShmemHugePagesBytes = &valBytes
 | |
| 		case "ShmemPmdMapped:":
 | |
| 			m.ShmemPmdMapped = &val
 | |
| 			m.ShmemPmdMappedBytes = &valBytes
 | |
| 		case "CmaTotal:":
 | |
| 			m.CmaTotal = &val
 | |
| 			m.CmaTotalBytes = &valBytes
 | |
| 		case "CmaFree:":
 | |
| 			m.CmaFree = &val
 | |
| 			m.CmaFreeBytes = &valBytes
 | |
| 		case "HugePages_Total:":
 | |
| 			m.HugePagesTotal = &val
 | |
| 		case "HugePages_Free:":
 | |
| 			m.HugePagesFree = &val
 | |
| 		case "HugePages_Rsvd:":
 | |
| 			m.HugePagesRsvd = &val
 | |
| 		case "HugePages_Surp:":
 | |
| 			m.HugePagesSurp = &val
 | |
| 		case "Hugepagesize:":
 | |
| 			m.Hugepagesize = &val
 | |
| 			m.HugepagesizeBytes = &valBytes
 | |
| 		case "DirectMap4k:":
 | |
| 			m.DirectMap4k = &val
 | |
| 			m.DirectMap4kBytes = &valBytes
 | |
| 		case "DirectMap2M:":
 | |
| 			m.DirectMap2M = &val
 | |
| 			m.DirectMap2MBytes = &valBytes
 | |
| 		case "DirectMap1G:":
 | |
| 			m.DirectMap1G = &val
 | |
| 			m.DirectMap1GBytes = &valBytes
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return &m, nil
 | |
| }
 |