mirror of
https://github.com/VictoriaMetrics/VictoriaMetrics.git
synced 2024-12-29 23:30:04 +01:00
390 lines
12 KiB
Go
390 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
|
|
}
|