1use anyhow::Result;
24use serde::{Deserialize, Serialize};
25use std::fs::read_to_string;
26
27use crate::traits::ToJson;
28
29#[derive(Debug, Serialize, Deserialize, Default, Clone)]
31pub struct VmStat {
32 pub nr_free_pages: Option<usize>,
33 pub nr_zone_inactive_anon: Option<usize>,
34 pub nr_zone_active_anon: Option<usize>,
35 pub nr_zone_inactive_file: Option<usize>,
36 pub nr_zone_active_file: Option<usize>,
37 pub nr_zone_unevictable: Option<usize>,
38 pub nr_zone_write_pending: Option<usize>,
39 pub nr_mlock: Option<usize>,
40 pub nr_bounce: Option<usize>,
41 pub nr_zspages: Option<usize>,
42 pub nr_free_cma: Option<usize>,
43 pub numa_hit: Option<usize>,
44 pub numa_miss: Option<usize>,
45 pub numa_foreign: Option<usize>,
46 pub numa_interleave: Option<usize>,
47 pub numa_local: Option<usize>,
48 pub numa_other: Option<usize>,
49 pub nr_inactive_anon: Option<usize>,
50 pub nr_active_anon: Option<usize>,
51 pub nr_inactive_file: Option<usize>,
52 pub nr_active_file: Option<usize>,
53 pub nr_unevictable: Option<usize>,
54 pub nr_slab_reclaimable: Option<usize>,
55 pub nr_slab_unreclaimable: Option<usize>,
56 pub nr_isolated_anon: Option<usize>,
57 pub nr_isolated_file: Option<usize>,
58 pub workingset_nodes: Option<usize>,
59 pub workingset_refault_anon: Option<usize>,
60 pub workingset_activate_anon: Option<usize>,
61 pub workingset_activate_file: Option<usize>,
62 pub workingset_restore_anon: Option<usize>,
63 pub workingset_restore_file: Option<usize>,
64 pub workingset_nodereclaim: Option<usize>,
65 pub nr_anon_pages: Option<usize>,
66 pub nr_mapped: Option<usize>,
67 pub nr_file_pages: Option<usize>,
68 pub nr_dirty: Option<usize>,
69 pub nr_writeback: Option<usize>,
70 pub nr_writeback_temp: Option<usize>,
71 pub nr_shmem: Option<usize>,
72 pub nr_shmem_hugepages: Option<usize>,
73 pub nr_shmem_pmdmapped: Option<usize>,
74 pub nr_file_hugepages: Option<usize>,
75 pub nr_file_pmdmapped: Option<usize>,
76 pub nr_anon_transparent_hugepages: Option<usize>,
77 pub nr_vmscan_write: Option<usize>,
78 pub nr_vmscan_immediate_reclaim: Option<usize>,
79 pub nr_dirtied: Option<usize>,
80 pub nr_written: Option<usize>,
81 pub nr_throttled_written: Option<usize>,
82 pub nr_kernel_misc_reclaimable: Option<usize>,
83 pub nr_foll_pin_acquired: Option<usize>,
84 pub nr_foll_pin_released: Option<usize>,
85 pub nr_kernel_stack: Option<usize>,
86 pub nr_page_table_pages: Option<usize>,
87 pub nr_sec_page_table_pages: Option<usize>,
88 pub nr_swapcached: Option<usize>,
89 pub pgpromote_success: Option<usize>,
90 pub pgpromote_candidate: Option<usize>,
91 pub nr_dirty_threshold: Option<usize>,
92 pub nr_dirty_background_threshold: Option<usize>,
93 pub pgpgin: Option<usize>,
94 pub pgpgout: Option<usize>,
95 pub pswpin: Option<usize>,
96 pub pswpout: Option<usize>,
97 pub pgalloc_dma: Option<usize>,
98 pub pgalloc_dma32: Option<usize>,
99 pub pgalloc_normal: Option<usize>,
100 pub pgalloc_movable: Option<usize>,
101 pub pgalloc_device: Option<usize>,
102 pub allocstall_dma: Option<usize>,
103 pub allocstall_dma32: Option<usize>,
104 pub allocstall_normal: Option<usize>,
105 pub allocstall_movable: Option<usize>,
106 pub allocstall_device: Option<usize>,
107 pub pgskip_dma: Option<usize>,
108 pub pgskip_dma32: Option<usize>,
109 pub pgskip_normal: Option<usize>,
110 pub pgskip_movable: Option<usize>,
111 pub pgskip_device: Option<usize>,
112 pub pgfree: Option<usize>,
113 pub pgactivate: Option<usize>,
114 pub pgdeactivate: Option<usize>,
115 pub pglazyfree: Option<usize>,
116 pub pgfault: Option<usize>,
117 pub pgmajfault: Option<usize>,
118 pub pglazyfreed: Option<usize>,
119 pub pgrefill: Option<usize>,
120 pub pgreuse: Option<usize>,
121 pub pgsteal_kswapd: Option<usize>,
122 pub pgsteal_direct: Option<usize>,
123 pub pgdemote_kswapd: Option<usize>,
124 pub pgdemote_direct: Option<usize>,
125 pub pgscan_kswapd: Option<usize>,
126 pub pgscan_direct: Option<usize>,
127 pub pgscan_direct_throttle: Option<usize>,
128 pub pgscan_anon: Option<usize>,
129 pub pgscan_file: Option<usize>,
130 pub pgsteal_anon: Option<usize>,
131 pub pgsteal_file: Option<usize>,
132 pub zone_reclaim_failed: Option<usize>,
133 pub pginodesteal: Option<usize>,
134 pub slabs_scanned: Option<usize>,
135 pub kswapd_inodesteal: Option<usize>,
136 pub kswapd_low_wmark_hit_quickly: Option<usize>,
137 pub kswapd_high_wmark_hit_quickly: Option<usize>,
138 pub pageoutrun: Option<usize>,
139 pub pgrotated: Option<usize>,
140 pub drop_pagecache: Option<usize>,
141 pub drop_slab: Option<usize>,
142 pub oom_kill: Option<usize>,
143 pub numa_pte_updates: Option<usize>,
144 pub numa_huge_pte_updates: Option<usize>,
145 pub numa_hint_faults: Option<usize>,
146 pub numa_hint_faults_local: Option<usize>,
147 pub numa_pages_migrated: Option<usize>,
148 pub pgmigrate_success: Option<usize>,
149 pub pgmigrate_fail: Option<usize>,
150 pub thp_migration_success: Option<usize>,
151 pub thp_migration_fail: Option<usize>,
152 pub thp_migration_split: Option<usize>,
153 pub compact_migrate_scanned: Option<usize>,
154 pub compact_free_scanned: Option<usize>,
155 pub compact_isolated: Option<usize>,
156 pub compact_stall: Option<usize>,
157 pub compact_fail: Option<usize>,
158 pub compact_success: Option<usize>,
159 pub compact_daemon_wake: Option<usize>,
160 pub compact_daemon_migrate_scanned: Option<usize>,
161 pub compact_daemon_free_scanned: Option<usize>,
162 pub htlb_buddy_alloc_success: Option<usize>,
163 pub htlb_buddy_alloc_fail: Option<usize>,
164 pub unevictable_pgs_culled: Option<usize>,
165 pub unevictable_pgs_scanned: Option<usize>,
166 pub unevictable_pgs_rescued: Option<usize>,
167 pub unevictable_pgs_mlocked: Option<usize>,
168 pub unevictable_pgs_munlocked: Option<usize>,
169 pub unevictable_pgs_cleared: Option<usize>,
170 pub unevictable_pgs_stranded: Option<usize>,
171 pub thp_fault_alloc: Option<usize>,
172 pub thp_fault_fallback: Option<usize>,
173 pub thp_fault_fallback_charge: Option<usize>,
174 pub thp_collapse_alloc: Option<usize>,
175 pub thp_collapse_alloc_failed: Option<usize>,
176 pub thp_file_alloc: Option<usize>,
177 pub thp_file_fallback: Option<usize>,
178 pub thp_file_mapped: Option<usize>,
179 pub thp_split_page: Option<usize>,
180 pub thp_split_page_failed: Option<usize>,
181 pub thp_deferred_split_page: Option<usize>,
182 pub thp_split_pmd: Option<usize>,
183 pub thp_scan_exceed_none_pte: Option<usize>,
184 pub thp_scan_exceed_swap_pte: Option<usize>,
185 pub thp_scan_exceed_share_pte: Option<usize>,
186 pub thp_split_pud: Option<usize>,
187 pub thp_zero_page_alloc: Option<usize>,
188 pub thp_zero_page_alloc_failed: Option<usize>,
189 pub thp_swpout: Option<usize>,
190 pub thp_swpout_fallback: Option<usize>,
191 pub balloon_inflate: Option<usize>,
192 pub balloon_deflate: Option<usize>,
193 pub balloon_migrate: Option<usize>,
194 pub swap_ra: Option<usize>,
195 pub swap_ra_hit: Option<usize>,
196 pub ksm_swpin_copy: Option<usize>,
197 pub cow_ksm: Option<usize>,
198 pub zswpin: Option<usize>,
199 pub zswpout: Option<usize>,
200 pub direct_map_level2_splits: Option<usize>,
201 pub direct_map_level3_splits: Option<usize>,
202 pub nr_unstable: Option<usize>,
203}
204
205impl VmStat {
206 pub fn new() -> Result<Self> {
207 let chunks = read_to_string("/proc/vmstat")?;
208 let chunks = chunks
209 .lines()
210 .map(|item| {
211 let mut items = item.trim().split_whitespace().map(|item| item.trim());
212 (items.next(), items.next())
213 })
214 .collect::<Vec<_>>();
215 let mut vmstat = VmStat::default();
216 for chunk in chunks {
217 match chunk {
218 (Some(key), Some(val)) => {
219 let value = val.parse::<usize>()?;
220 match key {
221 "nr_free_pages" => vmstat.nr_free_pages = Some(value),
222 "nr_zone_inactive_anon" => vmstat.nr_zone_inactive_anon = Some(value),
223 "nr_zone_active_anon" => vmstat.nr_zone_active_anon = Some(value),
224 "nr_zone_inactive_file" => vmstat.nr_zone_inactive_file = Some(value),
225 "nr_zone_active_file" => vmstat.nr_zone_active_file = Some(value),
226 "nr_zone_unevictable" => vmstat.nr_zone_unevictable = Some(value),
227 "nr_zone_write_pending" => vmstat.nr_zone_write_pending = Some(value),
228 "nr_mlock" => vmstat.nr_mlock = Some(value),
229 "nr_bounce" => vmstat.nr_bounce = Some(value),
230 "nr_zspages" => vmstat.nr_zspages = Some(value),
231 "nr_free_cma" => vmstat.nr_free_cma = Some(value),
232 "numa_hit" => vmstat.numa_hit = Some(value),
233 "numa_miss" => vmstat.numa_miss = Some(value),
234 "numa_foreign" => vmstat.numa_foreign = Some(value),
235 "numa_interleave" => vmstat.numa_interleave = Some(value),
236 "numa_local" => vmstat.numa_local = Some(value),
237 "numa_other" => vmstat.numa_other = Some(value),
238 "nr_inactive_anon" => vmstat.nr_inactive_anon = Some(value),
239 "nr_active_anon" => vmstat.nr_active_anon = Some(value),
240 "nr_inactive_file" => vmstat.nr_inactive_file = Some(value),
241 "nr_active_file" => vmstat.nr_active_file = Some(value),
242 "nr_unevictable" => vmstat.nr_unevictable = Some(value),
243 "nr_slab_reclaimable" => vmstat.nr_slab_reclaimable = Some(value),
244 "nr_slab_unreclaimable" => vmstat.nr_slab_unreclaimable = Some(value),
245 "nr_isolated_anon" => vmstat.nr_isolated_anon = Some(value),
246 "nr_isolated_file" => vmstat.nr_isolated_file = Some(value),
247 "workingset_nodes" => vmstat.workingset_nodes = Some(value),
248 "workingset_refault_anon" => vmstat.workingset_refault_anon = Some(value),
249 "workingset_activate_anon" => vmstat.workingset_activate_anon = Some(value),
250 "workingset_activate_file" => vmstat.workingset_activate_file = Some(value),
251 "workingset_restore_anon" => vmstat.workingset_restore_anon = Some(value),
252 "workingset_restore_file" => vmstat.workingset_restore_file = Some(value),
253 "workingset_nodereclaim" => vmstat.workingset_nodereclaim = Some(value),
254 "nr_anon_pages" => vmstat.nr_anon_pages = Some(value),
255 "nr_mapped" => vmstat.nr_mapped = Some(value),
256 "nr_file_pages" => vmstat.nr_file_pages = Some(value),
257 "nr_dirty" => vmstat.nr_dirty = Some(value),
258 "nr_writeback" => vmstat.nr_writeback = Some(value),
259 "nr_writeback_temp" => vmstat.nr_writeback_temp = Some(value),
260 "nr_shmem" => vmstat.nr_shmem = Some(value),
261 "nr_shmem_hugepages" => vmstat.nr_shmem_hugepages = Some(value),
262 "nr_shmem_pmdmapped" => vmstat.nr_shmem_pmdmapped = Some(value),
263 "nr_file_hugepages" => vmstat.nr_file_hugepages = Some(value),
264 "nr_file_pmdmapped" => vmstat.nr_file_pmdmapped = Some(value),
265 "nr_anon_transparent_hugepages" => {
266 vmstat.nr_anon_transparent_hugepages = Some(value)
267 }
268 "nr_vmscan_write" => vmstat.nr_vmscan_write = Some(value),
269 "nr_vmscan_immediate_reclaim" => {
270 vmstat.nr_vmscan_immediate_reclaim = Some(value)
271 }
272 "nr_dirtied" => vmstat.nr_dirtied = Some(value),
273 "nr_written" => vmstat.nr_written = Some(value),
274 "nr_throttled_written" => vmstat.nr_throttled_written = Some(value),
275 "nr_kernel_misc_reclaimable" => {
276 vmstat.nr_kernel_misc_reclaimable = Some(value)
277 }
278 "nr_foll_pin_acquired" => vmstat.nr_foll_pin_acquired = Some(value),
279 "nr_foll_pin_released" => vmstat.nr_foll_pin_released = Some(value),
280 "nr_kernel_stack" => vmstat.nr_kernel_stack = Some(value),
281 "nr_page_table_pages" => vmstat.nr_page_table_pages = Some(value),
282 "nr_sec_page_table_pages" => vmstat.nr_sec_page_table_pages = Some(value),
283 "nr_swapcached" => vmstat.nr_swapcached = Some(value),
284 "pgpromote_success" => vmstat.pgpromote_success = Some(value),
285 "pgpromote_candidate" => vmstat.pgpromote_candidate = Some(value),
286 "nr_dirty_threshold" => vmstat.nr_dirty_threshold = Some(value),
287 "nr_dirty_background_threshold" => {
288 vmstat.nr_dirty_background_threshold = Some(value)
289 }
290 "pgpgin" => vmstat.pgpgin = Some(value),
291 "pgpgout" => vmstat.pgpgout = Some(value),
292 "pswpin" => vmstat.pswpin = Some(value),
293 "pswpout" => vmstat.pswpout = Some(value),
294 "pgalloc_dma" => vmstat.pgalloc_dma = Some(value),
295 "pgalloc_dma32" => vmstat.pgalloc_dma32 = Some(value),
296 "pgalloc_normal" => vmstat.pgalloc_normal = Some(value),
297 "pgalloc_movable" => vmstat.pgalloc_movable = Some(value),
298 "pgalloc_device" => vmstat.pgalloc_device = Some(value),
299 "allocstall_dma" => vmstat.allocstall_dma = Some(value),
300 "allocstall_dma32" => vmstat.allocstall_dma32 = Some(value),
301 "allocstall_normal" => vmstat.allocstall_normal = Some(value),
302 "allocstall_movable" => vmstat.allocstall_movable = Some(value),
303 "allocstall_device" => vmstat.allocstall_device = Some(value),
304 "pgskip_dma" => vmstat.pgskip_dma = Some(value),
305 "pgskip_dma32" => vmstat.pgskip_dma32 = Some(value),
306 "pgskip_normal" => vmstat.pgskip_normal = Some(value),
307 "pgskip_movable" => vmstat.pgskip_movable = Some(value),
308 "pgskip_device" => vmstat.pgskip_device = Some(value),
309 "pgfree" => vmstat.pgfree = Some(value),
310 "pgactivate" => vmstat.pgactivate = Some(value),
311 "pgdeactivate" => vmstat.pgdeactivate = Some(value),
312 "pglazyfree" => vmstat.pglazyfree = Some(value),
313 "pgfault" => vmstat.pgfault = Some(value),
314 "pgmajfault" => vmstat.pgmajfault = Some(value),
315 "pglazyfreed" => vmstat.pglazyfreed = Some(value),
316 "pgrefill" => vmstat.pgrefill = Some(value),
317 "pgreuse" => vmstat.pgreuse = Some(value),
318 "pgsteal_kswapd" => vmstat.pgsteal_kswapd = Some(value),
319 "pgsteal_direct" => vmstat.pgsteal_direct = Some(value),
320 "pgdemote_kswapd" => vmstat.pgdemote_kswapd = Some(value),
321 "pgdemote_direct" => vmstat.pgdemote_direct = Some(value),
322 "pgscan_kswapd" => vmstat.pgscan_kswapd = Some(value),
323 "pgscan_direct" => vmstat.pgscan_direct = Some(value),
324 "pgscan_direct_throttle" => vmstat.pgscan_direct_throttle = Some(value),
325 "pgscan_anon" => vmstat.pgscan_anon = Some(value),
326 "pgscan_file" => vmstat.pgscan_file = Some(value),
327 "pgsteal_anon" => vmstat.pgsteal_anon = Some(value),
328 "pgsteal_file" => vmstat.pgsteal_file = Some(value),
329 "zone_reclaim_failed" => vmstat.zone_reclaim_failed = Some(value),
330 "pginodesteal" => vmstat.pginodesteal = Some(value),
331 "slabs_scanned" => vmstat.slabs_scanned = Some(value),
332 "kswapd_inodesteal" => vmstat.kswapd_inodesteal = Some(value),
333 "kswapd_low_wmark_hit_quickly" => {
334 vmstat.kswapd_low_wmark_hit_quickly = Some(value)
335 }
336 "kswapd_high_wmark_hit_quickly" => {
337 vmstat.kswapd_high_wmark_hit_quickly = Some(value)
338 }
339 "pageoutrun" => vmstat.pageoutrun = Some(value),
340 "pgrotated" => vmstat.pgrotated = Some(value),
341 "drop_pagecache" => vmstat.drop_pagecache = Some(value),
342 "drop_slab" => vmstat.drop_slab = Some(value),
343 "oom_kill" => vmstat.oom_kill = Some(value),
344 "numa_pte_updates" => vmstat.numa_pte_updates = Some(value),
345 "numa_huge_pte_updates" => vmstat.numa_huge_pte_updates = Some(value),
346 "numa_hint_faults" => vmstat.numa_hint_faults = Some(value),
347 "numa_hint_faults_local" => vmstat.numa_hint_faults_local = Some(value),
348 "numa_pages_migrated" => vmstat.numa_pages_migrated = Some(value),
349 "pgmigrate_success" => vmstat.pgmigrate_success = Some(value),
350 "pgmigrate_fail" => vmstat.pgmigrate_fail = Some(value),
351 "thp_migration_success" => vmstat.thp_migration_success = Some(value),
352 "thp_migration_fail" => vmstat.thp_migration_fail = Some(value),
353 "thp_migration_split" => vmstat.thp_migration_split = Some(value),
354 "compact_migrate_scanned" => vmstat.compact_migrate_scanned = Some(value),
355 "compact_free_scanned" => vmstat.compact_free_scanned = Some(value),
356 "compact_isolated" => vmstat.compact_isolated = Some(value),
357 "compact_stall" => vmstat.compact_stall = Some(value),
358 "compact_fail" => vmstat.compact_fail = Some(value),
359 "compact_success" => vmstat.compact_success = Some(value),
360 "compact_daemon_wake" => vmstat.compact_daemon_wake = Some(value),
361 "compact_daemon_migrate_scanned" => {
362 vmstat.compact_daemon_migrate_scanned = Some(value)
363 }
364 "compact_daemon_free_scanned" => {
365 vmstat.compact_daemon_free_scanned = Some(value)
366 }
367 "htlb_buddy_alloc_success" => vmstat.htlb_buddy_alloc_success = Some(value),
368 "htlb_buddy_alloc_fail" => vmstat.htlb_buddy_alloc_fail = Some(value),
369 "unevictable_pgs_culled" => vmstat.unevictable_pgs_culled = Some(value),
370 "unevictable_pgs_scanned" => vmstat.unevictable_pgs_scanned = Some(value),
371 "unevictable_pgs_rescued" => vmstat.unevictable_pgs_rescued = Some(value),
372 "unevictable_pgs_mlocked" => vmstat.unevictable_pgs_mlocked = Some(value),
373 "unevictable_pgs_munlocked" => {
374 vmstat.unevictable_pgs_munlocked = Some(value)
375 }
376 "unevictable_pgs_cleared" => vmstat.unevictable_pgs_cleared = Some(value),
377 "unevictable_pgs_stranded" => vmstat.unevictable_pgs_stranded = Some(value),
378 "thp_fault_alloc" => vmstat.thp_fault_alloc = Some(value),
379 "thp_fault_fallback" => vmstat.thp_fault_fallback = Some(value),
380 "thp_fault_fallback_charge" => {
381 vmstat.thp_fault_fallback_charge = Some(value)
382 }
383 "thp_collapse_alloc" => vmstat.thp_collapse_alloc = Some(value),
384 "thp_collapse_alloc_failed" => {
385 vmstat.thp_collapse_alloc_failed = Some(value)
386 }
387 "thp_file_alloc" => vmstat.thp_file_alloc = Some(value),
388 "thp_file_fallback" => vmstat.thp_file_fallback = Some(value),
389 "thp_file_mapped" => vmstat.thp_file_mapped = Some(value),
390 "thp_split_page" => vmstat.thp_split_page = Some(value),
391 "thp_split_page_failed" => vmstat.thp_split_page_failed = Some(value),
392 "thp_deferred_split_page" => vmstat.thp_deferred_split_page = Some(value),
393 "thp_split_pmd" => vmstat.thp_split_pmd = Some(value),
394 "thp_scan_exceed_none_pte" => vmstat.thp_scan_exceed_none_pte = Some(value),
395 "thp_scan_exceed_swap_pte" => vmstat.thp_scan_exceed_swap_pte = Some(value),
396 "thp_scan_exceed_share_pte" => {
397 vmstat.thp_scan_exceed_share_pte = Some(value)
398 }
399 "thp_split_pud" => vmstat.thp_split_pud = Some(value),
400 "thp_zero_page_alloc" => vmstat.thp_zero_page_alloc = Some(value),
401 "thp_zero_page_alloc_failed" => {
402 vmstat.thp_zero_page_alloc_failed = Some(value)
403 }
404 "thp_swpout" => vmstat.thp_swpout = Some(value),
405 "thp_swpout_fallback" => vmstat.thp_swpout_fallback = Some(value),
406 "balloon_inflate" => vmstat.balloon_inflate = Some(value),
407 "balloon_deflate" => vmstat.balloon_deflate = Some(value),
408 "balloon_migrate" => vmstat.balloon_migrate = Some(value),
409 "swap_ra" => vmstat.swap_ra = Some(value),
410 "swap_ra_hit" => vmstat.swap_ra_hit = Some(value),
411 "ksm_swpin_copy" => vmstat.ksm_swpin_copy = Some(value),
412 "cow_ksm" => vmstat.cow_ksm = Some(value),
413 "zswpin" => vmstat.zswpin = Some(value),
414 "zswpout" => vmstat.zswpout = Some(value),
415 "direct_map_level2_splits" => vmstat.direct_map_level2_splits = Some(value),
416 "direct_map_level3_splits" => vmstat.direct_map_level3_splits = Some(value),
417 "nr_unstable" => vmstat.nr_unstable = Some(value),
418 _ => continue,
419 }
420 }
421 _ => {}
422 }
423 }
424 Ok(vmstat)
425 }
426}
427
428impl ToJson for VmStat {}