[822] | 1 | // Copyright 2019 The Prometheus Authors
|
---|
| 2 | // Licensed under the Apache License, Version 2.0 (the "License");
|
---|
| 3 | // you may not use this file except in compliance with the License.
|
---|
| 4 | // You may obtain a copy of the License at
|
---|
| 5 | //
|
---|
| 6 | // http://www.apache.org/licenses/LICENSE-2.0
|
---|
| 7 | //
|
---|
| 8 | // Unless required by applicable law or agreed to in writing, software
|
---|
| 9 | // distributed under the License is distributed on an "AS IS" BASIS,
|
---|
| 10 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
---|
| 11 | // See the License for the specific language governing permissions and
|
---|
| 12 | // limitations under the License.
|
---|
| 13 |
|
---|
| 14 | package procfs
|
---|
| 15 |
|
---|
| 16 | import (
|
---|
| 17 | "bufio"
|
---|
| 18 | "bytes"
|
---|
| 19 | "fmt"
|
---|
| 20 | "io"
|
---|
| 21 | "strconv"
|
---|
| 22 | "strings"
|
---|
| 23 |
|
---|
| 24 | "github.com/prometheus/procfs/internal/util"
|
---|
| 25 | )
|
---|
| 26 |
|
---|
| 27 | // Meminfo represents memory statistics.
|
---|
| 28 | type Meminfo struct {
|
---|
| 29 | // Total usable ram (i.e. physical ram minus a few reserved
|
---|
| 30 | // bits and the kernel binary code)
|
---|
| 31 | MemTotal *uint64
|
---|
| 32 | // The sum of LowFree+HighFree
|
---|
| 33 | MemFree *uint64
|
---|
| 34 | // An estimate of how much memory is available for starting
|
---|
| 35 | // new applications, without swapping. Calculated from
|
---|
| 36 | // MemFree, SReclaimable, the size of the file LRU lists, and
|
---|
| 37 | // the low watermarks in each zone. The estimate takes into
|
---|
| 38 | // account that the system needs some page cache to function
|
---|
| 39 | // well, and that not all reclaimable slab will be
|
---|
| 40 | // reclaimable, due to items being in use. The impact of those
|
---|
| 41 | // factors will vary from system to system.
|
---|
| 42 | MemAvailable *uint64
|
---|
| 43 | // Relatively temporary storage for raw disk blocks shouldn't
|
---|
| 44 | // get tremendously large (20MB or so)
|
---|
| 45 | Buffers *uint64
|
---|
| 46 | Cached *uint64
|
---|
| 47 | // Memory that once was swapped out, is swapped back in but
|
---|
| 48 | // still also is in the swapfile (if memory is needed it
|
---|
| 49 | // doesn't need to be swapped out AGAIN because it is already
|
---|
| 50 | // in the swapfile. This saves I/O)
|
---|
| 51 | SwapCached *uint64
|
---|
| 52 | // Memory that has been used more recently and usually not
|
---|
| 53 | // reclaimed unless absolutely necessary.
|
---|
| 54 | Active *uint64
|
---|
| 55 | // Memory which has been less recently used. It is more
|
---|
| 56 | // eligible to be reclaimed for other purposes
|
---|
| 57 | Inactive *uint64
|
---|
| 58 | ActiveAnon *uint64
|
---|
| 59 | InactiveAnon *uint64
|
---|
| 60 | ActiveFile *uint64
|
---|
| 61 | InactiveFile *uint64
|
---|
| 62 | Unevictable *uint64
|
---|
| 63 | Mlocked *uint64
|
---|
| 64 | // total amount of swap space available
|
---|
| 65 | SwapTotal *uint64
|
---|
| 66 | // Memory which has been evicted from RAM, and is temporarily
|
---|
| 67 | // on the disk
|
---|
| 68 | SwapFree *uint64
|
---|
| 69 | // Memory which is waiting to get written back to the disk
|
---|
| 70 | Dirty *uint64
|
---|
| 71 | // Memory which is actively being written back to the disk
|
---|
| 72 | Writeback *uint64
|
---|
| 73 | // Non-file backed pages mapped into userspace page tables
|
---|
| 74 | AnonPages *uint64
|
---|
| 75 | // files which have been mapped, such as libraries
|
---|
| 76 | Mapped *uint64
|
---|
| 77 | Shmem *uint64
|
---|
| 78 | // in-kernel data structures cache
|
---|
| 79 | Slab *uint64
|
---|
| 80 | // Part of Slab, that might be reclaimed, such as caches
|
---|
| 81 | SReclaimable *uint64
|
---|
| 82 | // Part of Slab, that cannot be reclaimed on memory pressure
|
---|
| 83 | SUnreclaim *uint64
|
---|
| 84 | KernelStack *uint64
|
---|
| 85 | // amount of memory dedicated to the lowest level of page
|
---|
| 86 | // tables.
|
---|
| 87 | PageTables *uint64
|
---|
| 88 | // NFS pages sent to the server, but not yet committed to
|
---|
| 89 | // stable storage
|
---|
| 90 | NFSUnstable *uint64
|
---|
| 91 | // Memory used for block device "bounce buffers"
|
---|
| 92 | Bounce *uint64
|
---|
| 93 | // Memory used by FUSE for temporary writeback buffers
|
---|
| 94 | WritebackTmp *uint64
|
---|
| 95 | // Based on the overcommit ratio ('vm.overcommit_ratio'),
|
---|
| 96 | // this is the total amount of memory currently available to
|
---|
| 97 | // be allocated on the system. This limit is only adhered to
|
---|
| 98 | // if strict overcommit accounting is enabled (mode 2 in
|
---|
| 99 | // 'vm.overcommit_memory').
|
---|
| 100 | // The CommitLimit is calculated with the following formula:
|
---|
| 101 | // CommitLimit = ([total RAM pages] - [total huge TLB pages]) *
|
---|
| 102 | // overcommit_ratio / 100 + [total swap pages]
|
---|
| 103 | // For example, on a system with 1G of physical RAM and 7G
|
---|
| 104 | // of swap with a `vm.overcommit_ratio` of 30 it would
|
---|
| 105 | // yield a CommitLimit of 7.3G.
|
---|
| 106 | // For more details, see the memory overcommit documentation
|
---|
| 107 | // in vm/overcommit-accounting.
|
---|
| 108 | CommitLimit *uint64
|
---|
| 109 | // The amount of memory presently allocated on the system.
|
---|
| 110 | // The committed memory is a sum of all of the memory which
|
---|
| 111 | // has been allocated by processes, even if it has not been
|
---|
| 112 | // "used" by them as of yet. A process which malloc()'s 1G
|
---|
| 113 | // of memory, but only touches 300M of it will show up as
|
---|
| 114 | // using 1G. This 1G is memory which has been "committed" to
|
---|
| 115 | // by the VM and can be used at any time by the allocating
|
---|
| 116 | // application. With strict overcommit enabled on the system
|
---|
| 117 | // (mode 2 in 'vm.overcommit_memory'),allocations which would
|
---|
| 118 | // exceed the CommitLimit (detailed above) will not be permitted.
|
---|
| 119 | // This is useful if one needs to guarantee that processes will
|
---|
| 120 | // not fail due to lack of memory once that memory has been
|
---|
| 121 | // successfully allocated.
|
---|
| 122 | CommittedAS *uint64
|
---|
| 123 | // total size of vmalloc memory area
|
---|
| 124 | VmallocTotal *uint64
|
---|
| 125 | // amount of vmalloc area which is used
|
---|
| 126 | VmallocUsed *uint64
|
---|
| 127 | // largest contiguous block of vmalloc area which is free
|
---|
| 128 | VmallocChunk *uint64
|
---|
| 129 | HardwareCorrupted *uint64
|
---|
| 130 | AnonHugePages *uint64
|
---|
| 131 | ShmemHugePages *uint64
|
---|
| 132 | ShmemPmdMapped *uint64
|
---|
| 133 | CmaTotal *uint64
|
---|
| 134 | CmaFree *uint64
|
---|
| 135 | HugePagesTotal *uint64
|
---|
| 136 | HugePagesFree *uint64
|
---|
| 137 | HugePagesRsvd *uint64
|
---|
| 138 | HugePagesSurp *uint64
|
---|
| 139 | Hugepagesize *uint64
|
---|
| 140 | DirectMap4k *uint64
|
---|
| 141 | DirectMap2M *uint64
|
---|
| 142 | DirectMap1G *uint64
|
---|
| 143 | }
|
---|
| 144 |
|
---|
| 145 | // Meminfo returns an information about current kernel/system memory statistics.
|
---|
| 146 | // See https://www.kernel.org/doc/Documentation/filesystems/proc.txt
|
---|
| 147 | func (fs FS) Meminfo() (Meminfo, error) {
|
---|
| 148 | b, err := util.ReadFileNoStat(fs.proc.Path("meminfo"))
|
---|
| 149 | if err != nil {
|
---|
| 150 | return Meminfo{}, err
|
---|
| 151 | }
|
---|
| 152 |
|
---|
| 153 | m, err := parseMemInfo(bytes.NewReader(b))
|
---|
| 154 | if err != nil {
|
---|
| 155 | return Meminfo{}, fmt.Errorf("failed to parse meminfo: %w", err)
|
---|
| 156 | }
|
---|
| 157 |
|
---|
| 158 | return *m, nil
|
---|
| 159 | }
|
---|
| 160 |
|
---|
| 161 | func parseMemInfo(r io.Reader) (*Meminfo, error) {
|
---|
| 162 | var m Meminfo
|
---|
| 163 | s := bufio.NewScanner(r)
|
---|
| 164 | for s.Scan() {
|
---|
| 165 | // Each line has at least a name and value; we ignore the unit.
|
---|
| 166 | fields := strings.Fields(s.Text())
|
---|
| 167 | if len(fields) < 2 {
|
---|
| 168 | return nil, fmt.Errorf("malformed meminfo line: %q", s.Text())
|
---|
| 169 | }
|
---|
| 170 |
|
---|
| 171 | v, err := strconv.ParseUint(fields[1], 0, 64)
|
---|
| 172 | if err != nil {
|
---|
| 173 | return nil, err
|
---|
| 174 | }
|
---|
| 175 |
|
---|
| 176 | switch fields[0] {
|
---|
| 177 | case "MemTotal:":
|
---|
| 178 | m.MemTotal = &v
|
---|
| 179 | case "MemFree:":
|
---|
| 180 | m.MemFree = &v
|
---|
| 181 | case "MemAvailable:":
|
---|
| 182 | m.MemAvailable = &v
|
---|
| 183 | case "Buffers:":
|
---|
| 184 | m.Buffers = &v
|
---|
| 185 | case "Cached:":
|
---|
| 186 | m.Cached = &v
|
---|
| 187 | case "SwapCached:":
|
---|
| 188 | m.SwapCached = &v
|
---|
| 189 | case "Active:":
|
---|
| 190 | m.Active = &v
|
---|
| 191 | case "Inactive:":
|
---|
| 192 | m.Inactive = &v
|
---|
| 193 | case "Active(anon):":
|
---|
| 194 | m.ActiveAnon = &v
|
---|
| 195 | case "Inactive(anon):":
|
---|
| 196 | m.InactiveAnon = &v
|
---|
| 197 | case "Active(file):":
|
---|
| 198 | m.ActiveFile = &v
|
---|
| 199 | case "Inactive(file):":
|
---|
| 200 | m.InactiveFile = &v
|
---|
| 201 | case "Unevictable:":
|
---|
| 202 | m.Unevictable = &v
|
---|
| 203 | case "Mlocked:":
|
---|
| 204 | m.Mlocked = &v
|
---|
| 205 | case "SwapTotal:":
|
---|
| 206 | m.SwapTotal = &v
|
---|
| 207 | case "SwapFree:":
|
---|
| 208 | m.SwapFree = &v
|
---|
| 209 | case "Dirty:":
|
---|
| 210 | m.Dirty = &v
|
---|
| 211 | case "Writeback:":
|
---|
| 212 | m.Writeback = &v
|
---|
| 213 | case "AnonPages:":
|
---|
| 214 | m.AnonPages = &v
|
---|
| 215 | case "Mapped:":
|
---|
| 216 | m.Mapped = &v
|
---|
| 217 | case "Shmem:":
|
---|
| 218 | m.Shmem = &v
|
---|
| 219 | case "Slab:":
|
---|
| 220 | m.Slab = &v
|
---|
| 221 | case "SReclaimable:":
|
---|
| 222 | m.SReclaimable = &v
|
---|
| 223 | case "SUnreclaim:":
|
---|
| 224 | m.SUnreclaim = &v
|
---|
| 225 | case "KernelStack:":
|
---|
| 226 | m.KernelStack = &v
|
---|
| 227 | case "PageTables:":
|
---|
| 228 | m.PageTables = &v
|
---|
| 229 | case "NFS_Unstable:":
|
---|
| 230 | m.NFSUnstable = &v
|
---|
| 231 | case "Bounce:":
|
---|
| 232 | m.Bounce = &v
|
---|
| 233 | case "WritebackTmp:":
|
---|
| 234 | m.WritebackTmp = &v
|
---|
| 235 | case "CommitLimit:":
|
---|
| 236 | m.CommitLimit = &v
|
---|
| 237 | case "Committed_AS:":
|
---|
| 238 | m.CommittedAS = &v
|
---|
| 239 | case "VmallocTotal:":
|
---|
| 240 | m.VmallocTotal = &v
|
---|
| 241 | case "VmallocUsed:":
|
---|
| 242 | m.VmallocUsed = &v
|
---|
| 243 | case "VmallocChunk:":
|
---|
| 244 | m.VmallocChunk = &v
|
---|
| 245 | case "HardwareCorrupted:":
|
---|
| 246 | m.HardwareCorrupted = &v
|
---|
| 247 | case "AnonHugePages:":
|
---|
| 248 | m.AnonHugePages = &v
|
---|
| 249 | case "ShmemHugePages:":
|
---|
| 250 | m.ShmemHugePages = &v
|
---|
| 251 | case "ShmemPmdMapped:":
|
---|
| 252 | m.ShmemPmdMapped = &v
|
---|
| 253 | case "CmaTotal:":
|
---|
| 254 | m.CmaTotal = &v
|
---|
| 255 | case "CmaFree:":
|
---|
| 256 | m.CmaFree = &v
|
---|
| 257 | case "HugePages_Total:":
|
---|
| 258 | m.HugePagesTotal = &v
|
---|
| 259 | case "HugePages_Free:":
|
---|
| 260 | m.HugePagesFree = &v
|
---|
| 261 | case "HugePages_Rsvd:":
|
---|
| 262 | m.HugePagesRsvd = &v
|
---|
| 263 | case "HugePages_Surp:":
|
---|
| 264 | m.HugePagesSurp = &v
|
---|
| 265 | case "Hugepagesize:":
|
---|
| 266 | m.Hugepagesize = &v
|
---|
| 267 | case "DirectMap4k:":
|
---|
| 268 | m.DirectMap4k = &v
|
---|
| 269 | case "DirectMap2M:":
|
---|
| 270 | m.DirectMap2M = &v
|
---|
| 271 | case "DirectMap1G:":
|
---|
| 272 | m.DirectMap1G = &v
|
---|
| 273 | }
|
---|
| 274 | }
|
---|
| 275 |
|
---|
| 276 | return &m, nil
|
---|
| 277 | }
|
---|