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