blob: 4b2c4050a3df2bfe09701731dc32377f6801696b [file] [log] [blame]
khenaidood948f772021-08-11 17:49:24 -04001// 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
Abhay Kumara2ae5992025-11-10 14:02:24 +0000129 Percpu *uint64
khenaidood948f772021-08-11 17:49:24 -0400130 HardwareCorrupted *uint64
131 AnonHugePages *uint64
132 ShmemHugePages *uint64
133 ShmemPmdMapped *uint64
134 CmaTotal *uint64
135 CmaFree *uint64
136 HugePagesTotal *uint64
137 HugePagesFree *uint64
138 HugePagesRsvd *uint64
139 HugePagesSurp *uint64
140 Hugepagesize *uint64
141 DirectMap4k *uint64
142 DirectMap2M *uint64
143 DirectMap1G *uint64
Abhay Kumara2ae5992025-11-10 14:02:24 +0000144
145 // The struct fields below are the byte-normalized counterparts to the
146 // existing struct fields. Values are normalized using the optional
147 // unit field in the meminfo line.
148 MemTotalBytes *uint64
149 MemFreeBytes *uint64
150 MemAvailableBytes *uint64
151 BuffersBytes *uint64
152 CachedBytes *uint64
153 SwapCachedBytes *uint64
154 ActiveBytes *uint64
155 InactiveBytes *uint64
156 ActiveAnonBytes *uint64
157 InactiveAnonBytes *uint64
158 ActiveFileBytes *uint64
159 InactiveFileBytes *uint64
160 UnevictableBytes *uint64
161 MlockedBytes *uint64
162 SwapTotalBytes *uint64
163 SwapFreeBytes *uint64
164 DirtyBytes *uint64
165 WritebackBytes *uint64
166 AnonPagesBytes *uint64
167 MappedBytes *uint64
168 ShmemBytes *uint64
169 SlabBytes *uint64
170 SReclaimableBytes *uint64
171 SUnreclaimBytes *uint64
172 KernelStackBytes *uint64
173 PageTablesBytes *uint64
174 NFSUnstableBytes *uint64
175 BounceBytes *uint64
176 WritebackTmpBytes *uint64
177 CommitLimitBytes *uint64
178 CommittedASBytes *uint64
179 VmallocTotalBytes *uint64
180 VmallocUsedBytes *uint64
181 VmallocChunkBytes *uint64
182 PercpuBytes *uint64
183 HardwareCorruptedBytes *uint64
184 AnonHugePagesBytes *uint64
185 ShmemHugePagesBytes *uint64
186 ShmemPmdMappedBytes *uint64
187 CmaTotalBytes *uint64
188 CmaFreeBytes *uint64
189 HugepagesizeBytes *uint64
190 DirectMap4kBytes *uint64
191 DirectMap2MBytes *uint64
192 DirectMap1GBytes *uint64
khenaidood948f772021-08-11 17:49:24 -0400193}
194
195// Meminfo returns an information about current kernel/system memory statistics.
196// See https://www.kernel.org/doc/Documentation/filesystems/proc.txt
197func (fs FS) Meminfo() (Meminfo, error) {
198 b, err := util.ReadFileNoStat(fs.proc.Path("meminfo"))
199 if err != nil {
200 return Meminfo{}, err
201 }
202
203 m, err := parseMemInfo(bytes.NewReader(b))
204 if err != nil {
Abhay Kumara2ae5992025-11-10 14:02:24 +0000205 return Meminfo{}, fmt.Errorf("%w: %w", ErrFileParse, err)
khenaidood948f772021-08-11 17:49:24 -0400206 }
207
208 return *m, nil
209}
210
211func parseMemInfo(r io.Reader) (*Meminfo, error) {
212 var m Meminfo
213 s := bufio.NewScanner(r)
214 for s.Scan() {
khenaidood948f772021-08-11 17:49:24 -0400215 fields := strings.Fields(s.Text())
Abhay Kumara2ae5992025-11-10 14:02:24 +0000216 var val, valBytes uint64
khenaidood948f772021-08-11 17:49:24 -0400217
Abhay Kumara2ae5992025-11-10 14:02:24 +0000218 val, err := strconv.ParseUint(fields[1], 0, 64)
khenaidood948f772021-08-11 17:49:24 -0400219 if err != nil {
220 return nil, err
221 }
222
Abhay Kumara2ae5992025-11-10 14:02:24 +0000223 switch len(fields) {
224 case 2:
225 // No unit present, use the parsed the value as bytes directly.
226 valBytes = val
227 case 3:
228 // Unit present in optional 3rd field, convert it to
229 // bytes. The only unit supported within the Linux
230 // kernel is `kB`.
231 if fields[2] != "kB" {
232 return nil, fmt.Errorf("%w: Unsupported unit in optional 3rd field %q", ErrFileParse, fields[2])
233 }
234
235 valBytes = 1024 * val
236
237 default:
238 return nil, fmt.Errorf("%w: Malformed line %q", ErrFileParse, s.Text())
239 }
240
khenaidood948f772021-08-11 17:49:24 -0400241 switch fields[0] {
242 case "MemTotal:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000243 m.MemTotal = &val
244 m.MemTotalBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400245 case "MemFree:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000246 m.MemFree = &val
247 m.MemFreeBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400248 case "MemAvailable:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000249 m.MemAvailable = &val
250 m.MemAvailableBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400251 case "Buffers:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000252 m.Buffers = &val
253 m.BuffersBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400254 case "Cached:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000255 m.Cached = &val
256 m.CachedBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400257 case "SwapCached:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000258 m.SwapCached = &val
259 m.SwapCachedBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400260 case "Active:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000261 m.Active = &val
262 m.ActiveBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400263 case "Inactive:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000264 m.Inactive = &val
265 m.InactiveBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400266 case "Active(anon):":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000267 m.ActiveAnon = &val
268 m.ActiveAnonBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400269 case "Inactive(anon):":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000270 m.InactiveAnon = &val
271 m.InactiveAnonBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400272 case "Active(file):":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000273 m.ActiveFile = &val
274 m.ActiveFileBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400275 case "Inactive(file):":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000276 m.InactiveFile = &val
277 m.InactiveFileBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400278 case "Unevictable:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000279 m.Unevictable = &val
280 m.UnevictableBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400281 case "Mlocked:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000282 m.Mlocked = &val
283 m.MlockedBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400284 case "SwapTotal:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000285 m.SwapTotal = &val
286 m.SwapTotalBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400287 case "SwapFree:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000288 m.SwapFree = &val
289 m.SwapFreeBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400290 case "Dirty:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000291 m.Dirty = &val
292 m.DirtyBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400293 case "Writeback:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000294 m.Writeback = &val
295 m.WritebackBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400296 case "AnonPages:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000297 m.AnonPages = &val
298 m.AnonPagesBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400299 case "Mapped:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000300 m.Mapped = &val
301 m.MappedBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400302 case "Shmem:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000303 m.Shmem = &val
304 m.ShmemBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400305 case "Slab:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000306 m.Slab = &val
307 m.SlabBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400308 case "SReclaimable:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000309 m.SReclaimable = &val
310 m.SReclaimableBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400311 case "SUnreclaim:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000312 m.SUnreclaim = &val
313 m.SUnreclaimBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400314 case "KernelStack:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000315 m.KernelStack = &val
316 m.KernelStackBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400317 case "PageTables:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000318 m.PageTables = &val
319 m.PageTablesBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400320 case "NFS_Unstable:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000321 m.NFSUnstable = &val
322 m.NFSUnstableBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400323 case "Bounce:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000324 m.Bounce = &val
325 m.BounceBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400326 case "WritebackTmp:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000327 m.WritebackTmp = &val
328 m.WritebackTmpBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400329 case "CommitLimit:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000330 m.CommitLimit = &val
331 m.CommitLimitBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400332 case "Committed_AS:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000333 m.CommittedAS = &val
334 m.CommittedASBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400335 case "VmallocTotal:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000336 m.VmallocTotal = &val
337 m.VmallocTotalBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400338 case "VmallocUsed:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000339 m.VmallocUsed = &val
340 m.VmallocUsedBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400341 case "VmallocChunk:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000342 m.VmallocChunk = &val
343 m.VmallocChunkBytes = &valBytes
344 case "Percpu:":
345 m.Percpu = &val
346 m.PercpuBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400347 case "HardwareCorrupted:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000348 m.HardwareCorrupted = &val
349 m.HardwareCorruptedBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400350 case "AnonHugePages:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000351 m.AnonHugePages = &val
352 m.AnonHugePagesBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400353 case "ShmemHugePages:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000354 m.ShmemHugePages = &val
355 m.ShmemHugePagesBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400356 case "ShmemPmdMapped:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000357 m.ShmemPmdMapped = &val
358 m.ShmemPmdMappedBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400359 case "CmaTotal:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000360 m.CmaTotal = &val
361 m.CmaTotalBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400362 case "CmaFree:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000363 m.CmaFree = &val
364 m.CmaFreeBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400365 case "HugePages_Total:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000366 m.HugePagesTotal = &val
khenaidood948f772021-08-11 17:49:24 -0400367 case "HugePages_Free:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000368 m.HugePagesFree = &val
khenaidood948f772021-08-11 17:49:24 -0400369 case "HugePages_Rsvd:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000370 m.HugePagesRsvd = &val
khenaidood948f772021-08-11 17:49:24 -0400371 case "HugePages_Surp:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000372 m.HugePagesSurp = &val
khenaidood948f772021-08-11 17:49:24 -0400373 case "Hugepagesize:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000374 m.Hugepagesize = &val
375 m.HugepagesizeBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400376 case "DirectMap4k:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000377 m.DirectMap4k = &val
378 m.DirectMap4kBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400379 case "DirectMap2M:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000380 m.DirectMap2M = &val
381 m.DirectMap2MBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400382 case "DirectMap1G:":
Abhay Kumara2ae5992025-11-10 14:02:24 +0000383 m.DirectMap1G = &val
384 m.DirectMap1GBytes = &valBytes
khenaidood948f772021-08-11 17:49:24 -0400385 }
386 }
387
388 return &m, nil
389}