Bug 1689358 - Generate minidumps for child process crashes using the minidump-writer...
[gecko.git] / third_party / rust / procfs-core / src / meminfo.rs
blobb45268d41f397f65f2c7be2ff0fbe1b3a235d2e4
1 use super::{expect, from_str, ProcResult};
2 #[cfg(feature = "serde1")]
3 use serde::{Deserialize, Serialize};
4 use std::{collections::HashMap, io};
6 fn convert_to_kibibytes(num: u64, unit: &str) -> ProcResult<u64> {
7     match unit {
8         "B" => Ok(num),
9         "KiB" | "kiB" | "kB" | "KB" => Ok(num * 1024),
10         "MiB" | "miB" | "MB" | "mB" => Ok(num * 1024 * 1024),
11         "GiB" | "giB" | "GB" | "gB" => Ok(num * 1024 * 1024 * 1024),
12         unknown => Err(build_internal_error!(format!("Unknown unit type {}", unknown))),
13     }
16 /// This  struct  reports  statistics about memory usage on the system, based on
17 /// the `/proc/meminfo` file.
18 ///
19 /// It is used by `free(1)` to report the amount of free and used memory (both
20 /// physical  and  swap)  on  the  system  as well as the shared memory and
21 /// buffers used by the kernel.  Each struct member is generally reported in
22 /// bytes, but a few are unitless values.
23 ///
24 /// Except as noted below, all of the fields have been present since at least
25 /// Linux 2.6.0.  Some fields are optional and are present only if the kernel
26 /// was configured with various options; those dependencies are noted in the list.
27 ///
28 /// **Notes**
29 ///
30 /// While the file shows kilobytes (kB; 1 kB equals 1000 B),
31 /// it is actually kibibytes (KiB; 1 KiB equals 1024 B).
32 ///
33 /// All sizes are converted to bytes. Unitless values, like `hugepages_total` are not affected.
34 ///
35 /// This imprecision in /proc/meminfo is known,
36 /// but is not corrected due to legacy concerns -
37 /// programs rely on /proc/meminfo to specify size with the "kB" string.
38 ///
39 /// New fields to this struct may be added at any time (even without a major or minor semver bump).
40 #[derive(Debug, Clone)]
41 #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
42 #[allow(non_snake_case)]
43 #[non_exhaustive]
44 pub struct Meminfo {
45     /// Total usable RAM (i.e., physical RAM minus a few reserved bits and the kernel binary code).
46     pub mem_total: u64,
47     /// The sum of [LowFree](#structfield.low_free) + [HighFree](#structfield.high_free).
48     pub mem_free: u64,
49     /// An estimate of how much memory is available for starting new applications, without swapping.
50     ///
51     /// (since Linux 3.14)
52     pub mem_available: Option<u64>,
53     /// Relatively temporary storage for raw disk blocks that shouldn't get tremendously large (20MB or so).
54     pub buffers: u64,
55     /// In-memory cache for files read from the disk (the page cache).  Doesn't include SwapCached.
56     pub cached: u64,
57     /// Memory  that  once  was  swapped  out, is swapped back in but still also is in the swap
58     /// file.
59     ///
60     /// (If memory pressure is high, these pages don't need to be swapped out again
61     /// because they are already in the swap file.  This saves I/O.)
62     pub swap_cached: u64,
63     /// Memory that has been used more recently and usually not reclaimed unless absolutely
64     /// necessary.
65     pub active: u64,
66     /// Memory which has been less recently used.  It is more eligible to be reclaimed for other
67     /// purposes.
68     pub inactive: u64,
69     /// [To be documented.]
70     ///
71     /// (since Linux 2.6.28)
72     pub active_anon: Option<u64>,
73     /// [To be documented.]
74     ///
75     /// (since Linux 2.6.28)
76     pub inactive_anon: Option<u64>,
77     /// [To be documented.]
78     ///
79     /// (since Linux 2.6.28)
80     pub active_file: Option<u64>,
81     /// [To be documented.]
82     ///
83     /// (since Linux 2.6.28)
84     pub inactive_file: Option<u64>,
85     /// [To be documented.]
86     ///
87     /// (From Linux 2.6.28 to 2.6.30, CONFIG_UNEVICTABLE_LRU was required.)
88     pub unevictable: Option<u64>,
89     /// [To be documented.]
90     ///
91     /// (From Linux 2.6.28 to 2.6.30, CONFIG_UNEVICTABLE_LRU was required.)
92     pub mlocked: Option<u64>,
93     /// Total amount of highmem.
94     ///
95     /// Highmem is all memory above ~860MB of physical  memory.  Highmem areas are for use by
96     /// user-space programs, or for the page cache.  The kernel must use tricks to access this
97     /// memory, making it slower to access than lowmem.
98     ///
99     /// (Starting with Linux 2.6.19, CONFIG_HIGHMEM is required.)
100     pub high_total: Option<u64>,
101     /// Amount of free highmem.
102     ///
103     /// (Starting with Linux 2.6.19, CONFIG_HIGHMEM is required.)
104     pub high_free: Option<u64>,
105     /// Total amount of lowmem.
106     ///
107     /// Lowmem is memory which can be used for every thing  that highmem can be used for,
108     /// but it is also available for the kernel's use for its own data structures.
109     /// Among many other things, it is where everything from Slab is allocated.
110     /// Bad things happen when you're out of lowmem.
111     ///
112     /// (Starting with Linux 2.6.19, CONFIG_HIGHMEM is required.)
113     pub low_total: Option<u64>,
114     /// Amount of free lowmem.
115     ///
116     /// (Starting with Linux 2.6.19, CONFIG_HIGHMEM is required.)
117     pub low_free: Option<u64>,
118     /// [To be documented.]
119     ///
120     /// (since Linux 2.6.29.  CONFIG_MMU is required.)
121     pub mmap_copy: Option<u64>,
122     /// Total amount of swap space available.
123     pub swap_total: u64,
124     /// Amount of swap space that is currently unused.
125     pub swap_free: u64,
126     /// Memory which is waiting to get written back to the disk.
127     pub dirty: u64,
128     /// Memory which is actively being written back to the disk.
129     pub writeback: u64,
130     /// Non-file backed pages mapped into user-space page tables.
131     ///
132     /// (since Linux 2.6.18)
133     pub anon_pages: Option<u64>,
134     /// Files which have been mapped into memory (with mmap(2)), such as libraries.
135     pub mapped: u64,
136     /// Amount of memory consumed in tmpfs(5) filesystems.
137     ///
138     /// (since Linux 2.6.32)
139     pub shmem: Option<u64>,
140     /// In-kernel data structures cache.
141     pub slab: u64,
142     /// Part of Slab, that cannot be reclaimed on memory pressure.
143     ///
144     /// (since Linux 2.6.19)
145     pub s_reclaimable: Option<u64>,
146     /// Part of Slab, that cannot be reclaimed on memory pressure.
147     ///
148     /// (since Linux 2.6.19)
149     pub s_unreclaim: Option<u64>,
150     /// Amount of memory allocated to kernel stacks.
151     ///
152     /// (since Linux 2.6.32)
153     pub kernel_stack: Option<u64>,
154     /// Amount of memory dedicated to the lowest level of page tables.
155     ///
156     /// (since Linux 2.6.18)
157     pub page_tables: Option<u64>,
158     /// Amount of memory allocated for seconary page tables. This currently includes KVM mmu
159     /// allocations on x86 and arm64.
160     ///
161     /// (since Linux 6.1)
162     pub secondary_page_tables: Option<u64>,
163     /// [To be documented.]
164     ///
165     /// (CONFIG_QUICKLIST is required.  Since Linux 2.6.27)
166     pub quicklists: Option<u64>,
167     /// NFS pages sent to the server, but not yet committed to stable storage.
168     ///
169     /// (since Linux 2.6.18)
170     pub nfs_unstable: Option<u64>,
171     /// Memory used for block device "bounce buffers".
172     ///
173     /// (since Linux 2.6.18)
174     pub bounce: Option<u64>,
175     /// Memory used by FUSE for temporary writeback buffers.
176     ///
177     /// (since Linux 2.6.26)
178     pub writeback_tmp: Option<u64>,
179     /// This is the total amount of memory currently available to be allocated on the system,
180     /// expressed  in bytes.
181     ///
182     /// This  limit  is adhered  to  only if strict overcommit
183     /// accounting is enabled (mode 2 in /proc/sys/vm/overcommit_memory).  The limit is calculated
184     /// according to the formula described under /proc/sys/vm/overcommit_memory.  For further
185     /// details, see the kernel source  file
186     /// [Documentation/vm/overcommit-accounting](https://www.kernel.org/doc/Documentation/vm/overcommit-accounting).
187     ///
188     /// (since Linux 2.6.10)
189     pub commit_limit: Option<u64>,
190     /// The  amount of memory presently allocated on the system.
191     ///
192     /// The committed memory is a sum of all of the memory which has been allocated
193     /// by processes, even if it has not been "used" by them as of yet.  A process which allocates 1GB of memory  (using  malloc(3)
194     /// or  similar),  but  touches only 300MB of that memory will show up as using only 300MB of memory even if it has the address space
195     /// allocated for the entire 1GB.
196     ///
197     /// This 1GB is memory which has been "committed" to by the VM and can be used at any  time  by  the  allocating  application.   With
198     /// strict  overcommit  enabled  on  the  system  (mode 2 in /proc/sys/vm/overcommit_memory), allocations which would exceed the Committed_AS
199     /// mitLimit will not be permitted.  This is useful if one needs to guarantee that processes will not fail due to lack of memory once
200     /// that memory has been successfully allocated.
201     pub committed_as: u64,
202     /// Total size of vmalloc memory area.
203     pub vmalloc_total: u64,
204     /// Amount of vmalloc area which is used.
205     pub vmalloc_used: u64,
206     /// Largest contiguous block of vmalloc area which is free.
207     pub vmalloc_chunk: u64,
208     /// [To be documented.]
209     ///
210     /// (CONFIG_MEMORY_FAILURE is required.  Since Linux 2.6.32)
211     pub hardware_corrupted: Option<u64>,
212     /// Non-file backed huge pages mapped into user-space page tables.
213     ///
214     /// (CONFIG_TRANSPARENT_HUGEPAGE is required.  Since Linux 2.6.38)
215     pub anon_hugepages: Option<u64>,
216     /// Memory used by shared memory (shmem) and tmpfs(5) allocated with huge pages
217     ///
218     /// (CONFIG_TRANSPARENT_HUGEPAGE is required.  Since Linux 4.8)
219     pub shmem_hugepages: Option<u64>,
220     /// Shared memory mapped into user space with huge pages.
221     ///
222     /// (CONFIG_TRANSPARENT_HUGEPAGE is required.  Since Linux 4.8)
223     pub shmem_pmd_mapped: Option<u64>,
224     /// Total CMA (Contiguous Memory Allocator) pages.
225     ///
226     /// (CONFIG_CMA is required.  Since Linux 3.1)
227     pub cma_total: Option<u64>,
228     /// Free CMA (Contiguous Memory Allocator) pages.
229     ///
230     /// (CONFIG_CMA is required.  Since Linux 3.1)
231     pub cma_free: Option<u64>,
232     /// The size of the pool of huge pages.
233     ///
234     /// CONFIG_HUGETLB_PAGE is required.)
235     pub hugepages_total: Option<u64>,
236     /// The number of huge pages in the pool that are not yet allocated.
237     ///
238     /// (CONFIG_HUGETLB_PAGE is required.)
239     pub hugepages_free: Option<u64>,
240     /// This is the number of huge pages for which a commitment to allocate from the pool has been
241     /// made, but no allocation has yet been made.
242     ///
243     /// These reserved huge pages guarantee that an application will be able  to  allocate  a
244     /// huge page from the pool of huge pages at fault time.
245     ///
246     /// (CONFIG_HUGETLB_PAGE  is  required.  Since Linux 2.6.17)
247     pub hugepages_rsvd: Option<u64>,
248     /// This is the number of huge pages in the pool above the value in /proc/sys/vm/nr_hugepages.
249     ///
250     /// The maximum number of surplus huge pages is controlled by /proc/sys/vm/nr_overcommit_hugepages.
251     ///
252     /// (CONFIG_HUGETLB_PAGE  is  required.  Since Linux 2.6.24)
253     pub hugepages_surp: Option<u64>,
254     /// The size of huge pages.
255     ///
256     /// (CONFIG_HUGETLB_PAGE is required.)
257     pub hugepagesize: Option<u64>,
258     /// Number of bytes of RAM linearly mapped by kernel in 4kB pages.  (x86.)
259     ///
260     /// (since Linux 2.6.27)
261     pub direct_map_4k: Option<u64>,
262     /// Number of bytes of RAM linearly mapped by kernel in 4MB pages.
263     ///
264     /// (x86 with CONFIG_X86_64 or CONFIG_X86_PAE enabled.  Since Linux 2.6.27)
265     pub direct_map_4M: Option<u64>,
266     /// Number of bytes of RAM linearly mapped by kernel in 2MB pages.
267     ///
268     /// (x86 with neither CONFIG_X86_64 nor CONFIG_X86_PAE enabled.  Since Linux 2.6.27)
269     pub direct_map_2M: Option<u64>,
270     /// (x86 with CONFIG_X86_64 and CONFIG_X86_DIRECT_GBPAGES enabled.  Since Linux 2.6.27)
271     pub direct_map_1G: Option<u64>,
273     /// needs documentation
274     pub hugetlb: Option<u64>,
276     /// Memory allocated to the per-cpu alloctor used to back per-cpu allocations.
277     ///
278     /// This stat excludes the cost of metadata.
279     pub per_cpu: Option<u64>,
281     /// Kernel allocations that the kernel will attempt to reclaim under memory pressure.
282     ///
283     /// Includes s_reclaimable, and other direct allocations with a shrinker.
284     pub k_reclaimable: Option<u64>,
286     /// Undocumented field
287     ///
288     /// (CONFIG_TRANSPARENT_HUGEPAGE is requried.  Since Linux 5.4)
289     pub file_pmd_mapped: Option<u64>,
291     /// Undocumented field
292     ///
293     /// (CONFIG_TRANSPARENT_HUGEPAGE is required.  Since Linux 5.4)
294     pub file_huge_pages: Option<u64>,
296     /// Memory consumed by the zswap backend (compressed size).
297     ///
298     /// (CONFIG_ZSWAP is required.  Since Linux 5.19)
299     pub z_swap: Option<u64>,
301     /// Amount of anonymous memory stored in zswap (original size).
302     ///
303     /// (CONFIG_ZSWAP is required.  Since Linux 5.19)
304     pub z_swapped: Option<u64>,
307 impl super::FromBufRead for Meminfo {
308     fn from_buf_read<R: io::BufRead>(r: R) -> ProcResult<Self> {
309         let mut map = HashMap::new();
311         for line in r.lines() {
312             let line = expect!(line);
313             if line.is_empty() {
314                 continue;
315             }
316             let mut s = line.split_whitespace();
317             let field = expect!(s.next(), "no field");
318             let value = expect!(s.next(), "no value");
319             let unit = s.next(); // optional
321             let value = from_str!(u64, value);
323             let value = if let Some(unit) = unit {
324                 convert_to_kibibytes(value, unit)?
325             } else {
326                 value
327             };
329             map.insert(field[..field.len() - 1].to_string(), value);
330         }
332         // use 'remove' to move the value out of the hashmap
333         // if there's anything still left in the map at the end, that
334         // means we probably have a bug/typo, or are out-of-date
335         let meminfo = Meminfo {
336             mem_total: expect!(map.remove("MemTotal")),
337             mem_free: expect!(map.remove("MemFree")),
338             mem_available: map.remove("MemAvailable"),
339             buffers: expect!(map.remove("Buffers")),
340             cached: expect!(map.remove("Cached")),
341             swap_cached: expect!(map.remove("SwapCached")),
342             active: expect!(map.remove("Active")),
343             inactive: expect!(map.remove("Inactive")),
344             active_anon: map.remove("Active(anon)"),
345             inactive_anon: map.remove("Inactive(anon)"),
346             active_file: map.remove("Active(file)"),
347             inactive_file: map.remove("Inactive(file)"),
348             unevictable: map.remove("Unevictable"),
349             mlocked: map.remove("Mlocked"),
350             high_total: map.remove("HighTotal"),
351             high_free: map.remove("HighFree"),
352             low_total: map.remove("LowTotal"),
353             low_free: map.remove("LowFree"),
354             mmap_copy: map.remove("MmapCopy"),
355             swap_total: expect!(map.remove("SwapTotal")),
356             swap_free: expect!(map.remove("SwapFree")),
357             dirty: expect!(map.remove("Dirty")),
358             writeback: expect!(map.remove("Writeback")),
359             anon_pages: map.remove("AnonPages"),
360             mapped: expect!(map.remove("Mapped")),
361             shmem: map.remove("Shmem"),
362             slab: expect!(map.remove("Slab")),
363             s_reclaimable: map.remove("SReclaimable"),
364             s_unreclaim: map.remove("SUnreclaim"),
365             kernel_stack: map.remove("KernelStack"),
366             page_tables: map.remove("PageTables"),
367             secondary_page_tables: map.remove("SecPageTables"),
368             quicklists: map.remove("Quicklists"),
369             nfs_unstable: map.remove("NFS_Unstable"),
370             bounce: map.remove("Bounce"),
371             writeback_tmp: map.remove("WritebackTmp"),
372             commit_limit: map.remove("CommitLimit"),
373             committed_as: expect!(map.remove("Committed_AS")),
374             vmalloc_total: expect!(map.remove("VmallocTotal")),
375             vmalloc_used: expect!(map.remove("VmallocUsed")),
376             vmalloc_chunk: expect!(map.remove("VmallocChunk")),
377             hardware_corrupted: map.remove("HardwareCorrupted"),
378             anon_hugepages: map.remove("AnonHugePages"),
379             shmem_hugepages: map.remove("ShmemHugePages"),
380             shmem_pmd_mapped: map.remove("ShmemPmdMapped"),
381             cma_total: map.remove("CmaTotal"),
382             cma_free: map.remove("CmaFree"),
383             hugepages_total: map.remove("HugePages_Total"),
384             hugepages_free: map.remove("HugePages_Free"),
385             hugepages_rsvd: map.remove("HugePages_Rsvd"),
386             hugepages_surp: map.remove("HugePages_Surp"),
387             hugepagesize: map.remove("Hugepagesize"),
388             direct_map_4k: map.remove("DirectMap4k"),
389             direct_map_4M: map.remove("DirectMap4M"),
390             direct_map_2M: map.remove("DirectMap2M"),
391             direct_map_1G: map.remove("DirectMap1G"),
392             k_reclaimable: map.remove("KReclaimable"),
393             per_cpu: map.remove("Percpu"),
394             hugetlb: map.remove("Hugetlb"),
395             file_pmd_mapped: map.remove("FilePmdMapped"),
396             file_huge_pages: map.remove("FileHugePages"),
397             z_swap: map.remove("Zswap"),
398             z_swapped: map.remove("Zswapped"),
399         };
401         if cfg!(test) {
402             assert!(map.is_empty(), "meminfo map is not empty: {:#?}", map);
403         }
405         Ok(meminfo)
406     }