blob: f65e174e57b3aa479f92faddcad7a35873617936 [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
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}