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 14package procfs 15 16import ( 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. 28type 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 147func (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 161func 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} 278