123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389 |
- // 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
- }
|