diff options
Diffstat (limited to '')
-rw-r--r-- | library/vmstat.c | 1513 |
1 files changed, 1513 insertions, 0 deletions
diff --git a/library/vmstat.c b/library/vmstat.c new file mode 100644 index 0000000..f9ae715 --- /dev/null +++ b/library/vmstat.c @@ -0,0 +1,1513 @@ +/* + * vmstat.c - virtual memory related definitions for libproc2 + * + * Copyright © 2015-2023 Jim Warner <james.warner@comcast.net> + * Copyright © 2015-2023 Craig Small <csmall@dropbear.xyz> + * Copyright © 2003 Albert Cahalan + * Copyright © 1996 Charles Blake <cblake@bbn.com> + * Copyright © 1995 Martin Schulze <joey@infodrom.north.de> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include <errno.h> +#include <fcntl.h> +#include <search.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <unistd.h> + +#include <sys/stat.h> +#include <sys/types.h> + +#include "procps-private.h" +#include "vmstat.h" + + +#define VMSTAT_FILE "/proc/vmstat" +#define VMSTAT_BUFF 8192 + +/* ------------------------------------------------------------- + + this provision can be used to help ensure that our Item_table | + was synchronized with the enumerators found in the associated | + header file. It's intended to be used locally (& temporarily) | + at least once at some point prior to publishing new releases! | */ +// #define ITEMTABLE_DEBUG //----------------------------------- | +// ------------------------------------------------------------- + + +/* + * Perhaps someday we'll all learn what is in these fields. But | + * that might require available linux documentation progressing | + * beyond a state that was acknowledged in the following thread | + * + * http://www.spinics.net/lists/linux-man/msg09096.html + */ +struct vmstat_data { + unsigned long allocstall_dma; + unsigned long allocstall_dma32; + unsigned long allocstall_high; + unsigned long allocstall_movable; + unsigned long allocstall_normal; + unsigned long balloon_deflate; + unsigned long balloon_inflate; + unsigned long balloon_migrate; + unsigned long compact_daemon_free_scanned; + unsigned long compact_daemon_migrate_scanned; + unsigned long compact_daemon_wake; + unsigned long compact_fail; + unsigned long compact_free_scanned; + unsigned long compact_isolated; + unsigned long compact_migrate_scanned; + unsigned long compact_stall; + unsigned long compact_success; + unsigned long drop_pagecache; + unsigned long drop_slab; + unsigned long htlb_buddy_alloc_fail; + unsigned long htlb_buddy_alloc_success; + unsigned long kswapd_high_wmark_hit_quickly; + unsigned long kswapd_inodesteal; + unsigned long kswapd_low_wmark_hit_quickly; + unsigned long nr_active_anon; + unsigned long nr_active_file; + unsigned long nr_anon_pages; + unsigned long nr_anon_transparent_hugepages; + unsigned long nr_bounce; + unsigned long nr_dirtied; + unsigned long nr_dirty; + unsigned long nr_dirty_background_threshold; + unsigned long nr_dirty_threshold; + unsigned long nr_file_hugepages; + unsigned long nr_file_pages; + unsigned long nr_file_pmdmapped; + unsigned long nr_foll_pin_acquired; + unsigned long nr_foll_pin_released; + unsigned long nr_free_cma; + unsigned long nr_free_pages; + unsigned long nr_inactive_anon; + unsigned long nr_inactive_file; + unsigned long nr_isolated_anon; + unsigned long nr_isolated_file; + unsigned long nr_kernel_misc_reclaimable; + unsigned long nr_kernel_stack; + unsigned long nr_mapped; + unsigned long nr_mlock; + unsigned long nr_page_table_pages; + unsigned long nr_shadow_call_stack; + unsigned long nr_shmem; + unsigned long nr_shmem_hugepages; + unsigned long nr_shmem_pmdmapped; + unsigned long nr_slab_reclaimable; + unsigned long nr_slab_unreclaimable; +/* nr_tlb_local_flush_all; CONFIG_DEBUG_TLBFLUSH only */ +/* nr_tlb_local_flush_one; CONFIG_DEBUG_TLBFLUSH only */ +/* nr_tlb_remote_flush; CONFIG_DEBUG_TLBFLUSH only */ +/* nr_tlb_remote_flush_received; CONFIG_DEBUG_TLBFLUSH only */ + unsigned long nr_unevictable; + unsigned long nr_unstable; + unsigned long nr_vmscan_immediate_reclaim; + unsigned long nr_vmscan_write; + unsigned long nr_writeback; + unsigned long nr_writeback_temp; + unsigned long nr_written; + unsigned long nr_zone_active_anon; + unsigned long nr_zone_active_file; + unsigned long nr_zone_inactive_anon; + unsigned long nr_zone_inactive_file; + unsigned long nr_zone_unevictable; + unsigned long nr_zone_write_pending; + unsigned long nr_zspages; + unsigned long numa_foreign; + unsigned long numa_hint_faults; + unsigned long numa_hint_faults_local; + unsigned long numa_hit; + unsigned long numa_huge_pte_updates; + unsigned long numa_interleave; + unsigned long numa_local; + unsigned long numa_miss; + unsigned long numa_other; + unsigned long numa_pages_migrated; + unsigned long numa_pte_updates; + unsigned long oom_kill; + unsigned long pageoutrun; + unsigned long pgactivate; + unsigned long pgalloc_dma; + unsigned long pgalloc_dma32; + unsigned long pgalloc_high; + unsigned long pgalloc_movable; + unsigned long pgalloc_normal; + unsigned long pgdeactivate; + unsigned long pgfault; + unsigned long pgfree; + unsigned long pginodesteal; + unsigned long pglazyfree; + unsigned long pglazyfreed; + unsigned long pgmajfault; + unsigned long pgmigrate_fail; + unsigned long pgmigrate_success; + unsigned long pgpgin; + unsigned long pgpgout; + unsigned long pgrefill; + unsigned long pgrotated; + unsigned long pgscan_anon; + unsigned long pgscan_direct; + unsigned long pgscan_direct_throttle; + unsigned long pgscan_file; + unsigned long pgscan_kswapd; + unsigned long pgskip_dma; + unsigned long pgskip_dma32; + unsigned long pgskip_high; + unsigned long pgskip_movable; + unsigned long pgskip_normal; + unsigned long pgsteal_anon; + unsigned long pgsteal_direct; + unsigned long pgsteal_file; + unsigned long pgsteal_kswapd; + unsigned long pswpin; + unsigned long pswpout; + unsigned long slabs_scanned; + unsigned long swap_ra; + unsigned long swap_ra_hit; + unsigned long thp_collapse_alloc; + unsigned long thp_collapse_alloc_failed; + unsigned long thp_deferred_split_page; + unsigned long thp_fault_alloc; + unsigned long thp_fault_fallback; + unsigned long thp_fault_fallback_charge; + unsigned long thp_file_alloc; + unsigned long thp_file_fallback; + unsigned long thp_file_fallback_charge; + unsigned long thp_file_mapped; + unsigned long thp_split_page; + unsigned long thp_split_page_failed; + unsigned long thp_split_pmd; + unsigned long thp_split_pud; + unsigned long thp_swpout; + unsigned long thp_swpout_fallback; + unsigned long thp_zero_page_alloc; + unsigned long thp_zero_page_alloc_failed; + unsigned long unevictable_pgs_cleared; + unsigned long unevictable_pgs_culled; + unsigned long unevictable_pgs_mlocked; + unsigned long unevictable_pgs_munlocked; + unsigned long unevictable_pgs_rescued; + unsigned long unevictable_pgs_scanned; + unsigned long unevictable_pgs_stranded; +/* vmacache_find_calls; CONFIG_DEBUG_VM_VMACACHE only */ +/* vmacache_find_hits; CONFIG_DEBUG_VM_VMACACHE only */ + unsigned long workingset_activate; + unsigned long workingset_nodereclaim; + unsigned long workingset_nodes; + unsigned long workingset_refault; + unsigned long workingset_restore; + unsigned long zone_reclaim_failed; +}; + +struct vmstat_hist { + struct vmstat_data new; + struct vmstat_data old; +}; + +struct stacks_extent { + int ext_numstacks; + struct stacks_extent *next; + struct vmstat_stack **stacks; +}; + +struct vmstat_info { + int refcount; + int vmstat_fd; + struct vmstat_hist hist; + int numitems; + enum vmstat_item *items; + struct stacks_extent *extents; + struct hsearch_data hashtab; + struct vmstat_result get_this; + time_t sav_secs; +}; + + +// ___ Results 'Set' Support |||||||||||||||||||||||||||||||||||||||||||||||||| + +#define setNAME(e) set_vmstat_ ## e +#define setDECL(e) static void setNAME(e) \ + (struct vmstat_result *R, struct vmstat_hist *H) + +// regular assignment +#define REG_set(e,x) setDECL(e) { R->result.ul_int = H->new. x; } +// delta assignment +#define HST_set(e,x) setDECL(e) { R->result.sl_int = ( H->new. x - H->old. x ); } + +setDECL(noop) { (void)R; (void)H; } +setDECL(extra) { (void)H; R->result.ul_int = 0; } + +REG_set(ALLOCSTALL_DMA, allocstall_dma) +REG_set(ALLOCSTALL_DMA32, allocstall_dma32) +REG_set(ALLOCSTALL_HIGH, allocstall_high) +REG_set(ALLOCSTALL_MOVABLE, allocstall_movable) +REG_set(ALLOCSTALL_NORMAL, allocstall_normal) +REG_set(BALLOON_DEFLATE, balloon_deflate) +REG_set(BALLOON_INFLATE, balloon_inflate) +REG_set(BALLOON_MIGRATE, balloon_migrate) +REG_set(COMPACT_DAEMON_FREE_SCANNED, compact_daemon_free_scanned) +REG_set(COMPACT_DAEMON_MIGRATE_SCANNED, compact_daemon_migrate_scanned) +REG_set(COMPACT_DAEMON_WAKE, compact_daemon_wake) +REG_set(COMPACT_FAIL, compact_fail) +REG_set(COMPACT_FREE_SCANNED, compact_free_scanned) +REG_set(COMPACT_ISOLATED, compact_isolated) +REG_set(COMPACT_MIGRATE_SCANNED, compact_migrate_scanned) +REG_set(COMPACT_STALL, compact_stall) +REG_set(COMPACT_SUCCESS, compact_success) +REG_set(DROP_PAGECACHE, drop_pagecache) +REG_set(DROP_SLAB, drop_slab) +REG_set(HTLB_BUDDY_ALLOC_FAIL, htlb_buddy_alloc_fail) +REG_set(HTLB_BUDDY_ALLOC_SUCCESS, htlb_buddy_alloc_success) +REG_set(KSWAPD_HIGH_WMARK_HIT_QUICKLY, kswapd_high_wmark_hit_quickly) +REG_set(KSWAPD_INODESTEAL, kswapd_inodesteal) +REG_set(KSWAPD_LOW_WMARK_HIT_QUICKLY, kswapd_low_wmark_hit_quickly) +REG_set(NR_ACTIVE_ANON, nr_active_anon) +REG_set(NR_ACTIVE_FILE, nr_active_file) +REG_set(NR_ANON_PAGES, nr_anon_pages) +REG_set(NR_ANON_TRANSPARENT_HUGEPAGES, nr_anon_transparent_hugepages) +REG_set(NR_BOUNCE, nr_bounce) +REG_set(NR_DIRTIED, nr_dirtied) +REG_set(NR_DIRTY, nr_dirty) +REG_set(NR_DIRTY_BACKGROUND_THRESHOLD, nr_dirty_background_threshold) +REG_set(NR_DIRTY_THRESHOLD, nr_dirty_threshold) +REG_set(NR_FILE_HUGEPAGES, nr_file_hugepages) +REG_set(NR_FILE_PAGES, nr_file_pages) +REG_set(NR_FILE_PMDMAPPED, nr_file_pmdmapped) +REG_set(NR_FOLL_PIN_ACQUIRED, nr_foll_pin_acquired) +REG_set(NR_FOLL_PIN_RELEASED, nr_foll_pin_released) +REG_set(NR_FREE_CMA, nr_free_cma) +REG_set(NR_FREE_PAGES, nr_free_pages) +REG_set(NR_INACTIVE_ANON, nr_inactive_anon) +REG_set(NR_INACTIVE_FILE, nr_inactive_file) +REG_set(NR_ISOLATED_ANON, nr_isolated_anon) +REG_set(NR_ISOLATED_FILE, nr_isolated_file) +REG_set(NR_KERNEL_MISC_RECLAIMABLE, nr_kernel_misc_reclaimable) +REG_set(NR_KERNEL_STACK, nr_kernel_stack) +REG_set(NR_MAPPED, nr_mapped) +REG_set(NR_MLOCK, nr_mlock) +REG_set(NR_PAGE_TABLE_PAGES, nr_page_table_pages) +REG_set(NR_SHADOW_CALL_STACK, nr_shadow_call_stack) +REG_set(NR_SHMEM, nr_shmem) +REG_set(NR_SHMEM_HUGEPAGES, nr_shmem_hugepages) +REG_set(NR_SHMEM_PMDMAPPED, nr_shmem_pmdmapped) +REG_set(NR_SLAB_RECLAIMABLE, nr_slab_reclaimable) +REG_set(NR_SLAB_UNRECLAIMABLE, nr_slab_unreclaimable) +REG_set(NR_UNEVICTABLE, nr_unevictable) +REG_set(NR_UNSTABLE, nr_unstable) +REG_set(NR_VMSCAN_IMMEDIATE_RECLAIM, nr_vmscan_immediate_reclaim) +REG_set(NR_VMSCAN_WRITE, nr_vmscan_write) +REG_set(NR_WRITEBACK, nr_writeback) +REG_set(NR_WRITEBACK_TEMP, nr_writeback_temp) +REG_set(NR_WRITTEN, nr_written) +REG_set(NR_ZONE_ACTIVE_ANON, nr_zone_active_anon) +REG_set(NR_ZONE_ACTIVE_FILE, nr_zone_active_file) +REG_set(NR_ZONE_INACTIVE_ANON, nr_zone_inactive_anon) +REG_set(NR_ZONE_INACTIVE_FILE, nr_zone_inactive_file) +REG_set(NR_ZONE_UNEVICTABLE, nr_zone_unevictable) +REG_set(NR_ZONE_WRITE_PENDING, nr_zone_write_pending) +REG_set(NR_ZSPAGES, nr_zspages) +REG_set(NUMA_FOREIGN, numa_foreign) +REG_set(NUMA_HINT_FAULTS, numa_hint_faults) +REG_set(NUMA_HINT_FAULTS_LOCAL, numa_hint_faults_local) +REG_set(NUMA_HIT, numa_hit) +REG_set(NUMA_HUGE_PTE_UPDATES, numa_huge_pte_updates) +REG_set(NUMA_INTERLEAVE, numa_interleave) +REG_set(NUMA_LOCAL, numa_local) +REG_set(NUMA_MISS, numa_miss) +REG_set(NUMA_OTHER, numa_other) +REG_set(NUMA_PAGES_MIGRATED, numa_pages_migrated) +REG_set(NUMA_PTE_UPDATES, numa_pte_updates) +REG_set(OOM_KILL, oom_kill) +REG_set(PAGEOUTRUN, pageoutrun) +REG_set(PGACTIVATE, pgactivate) +REG_set(PGALLOC_DMA, pgalloc_dma) +REG_set(PGALLOC_DMA32, pgalloc_dma32) +REG_set(PGALLOC_HIGH, pgalloc_high) +REG_set(PGALLOC_MOVABLE, pgalloc_movable) +REG_set(PGALLOC_NORMAL, pgalloc_normal) +REG_set(PGDEACTIVATE, pgdeactivate) +REG_set(PGFAULT, pgfault) +REG_set(PGFREE, pgfree) +REG_set(PGINODESTEAL, pginodesteal) +REG_set(PGLAZYFREE, pglazyfree) +REG_set(PGLAZYFREED, pglazyfreed) +REG_set(PGMAJFAULT, pgmajfault) +REG_set(PGMIGRATE_FAIL, pgmigrate_fail) +REG_set(PGMIGRATE_SUCCESS, pgmigrate_success) +REG_set(PGPGIN, pgpgin) +REG_set(PGPGOUT, pgpgout) +REG_set(PGREFILL, pgrefill) +REG_set(PGROTATED, pgrotated) +REG_set(PGSCAN_ANON, pgscan_anon) +REG_set(PGSCAN_DIRECT, pgscan_direct) +REG_set(PGSCAN_DIRECT_THROTTLE, pgscan_direct_throttle) +REG_set(PGSCAN_FILE, pgscan_file) +REG_set(PGSCAN_KSWAPD, pgscan_kswapd) +REG_set(PGSKIP_DMA, pgskip_dma) +REG_set(PGSKIP_DMA32, pgskip_dma32) +REG_set(PGSKIP_HIGH, pgskip_high) +REG_set(PGSKIP_MOVABLE, pgskip_movable) +REG_set(PGSKIP_NORMAL, pgskip_normal) +REG_set(PGSTEAL_ANON, pgsteal_anon) +REG_set(PGSTEAL_DIRECT, pgsteal_direct) +REG_set(PGSTEAL_FILE, pgsteal_file) +REG_set(PGSTEAL_KSWAPD, pgsteal_kswapd) +REG_set(PSWPIN, pswpin) +REG_set(PSWPOUT, pswpout) +REG_set(SLABS_SCANNED, slabs_scanned) +REG_set(SWAP_RA, swap_ra) +REG_set(SWAP_RA_HIT, swap_ra_hit) +REG_set(THP_COLLAPSE_ALLOC, thp_collapse_alloc) +REG_set(THP_COLLAPSE_ALLOC_FAILED, thp_collapse_alloc_failed) +REG_set(THP_DEFERRED_SPLIT_PAGE, thp_deferred_split_page) +REG_set(THP_FAULT_ALLOC, thp_fault_alloc) +REG_set(THP_FAULT_FALLBACK, thp_fault_fallback) +REG_set(THP_FAULT_FALLBACK_CHARGE, thp_fault_fallback_charge) +REG_set(THP_FILE_ALLOC, thp_file_alloc) +REG_set(THP_FILE_FALLBACK, thp_file_fallback) +REG_set(THP_FILE_FALLBACK_CHARGE, thp_file_fallback_charge) +REG_set(THP_FILE_MAPPED, thp_file_mapped) +REG_set(THP_SPLIT_PAGE, thp_split_page) +REG_set(THP_SPLIT_PAGE_FAILED, thp_split_page_failed) +REG_set(THP_SPLIT_PMD, thp_split_pmd) +REG_set(THP_SPLIT_PUD, thp_split_pud) +REG_set(THP_SWPOUT, thp_swpout) +REG_set(THP_SWPOUT_FALLBACK, thp_swpout_fallback) +REG_set(THP_ZERO_PAGE_ALLOC, thp_zero_page_alloc) +REG_set(THP_ZERO_PAGE_ALLOC_FAILED, thp_zero_page_alloc_failed) +REG_set(UNEVICTABLE_PGS_CLEARED, unevictable_pgs_cleared) +REG_set(UNEVICTABLE_PGS_CULLED, unevictable_pgs_culled) +REG_set(UNEVICTABLE_PGS_MLOCKED, unevictable_pgs_mlocked) +REG_set(UNEVICTABLE_PGS_MUNLOCKED, unevictable_pgs_munlocked) +REG_set(UNEVICTABLE_PGS_RESCUED, unevictable_pgs_rescued) +REG_set(UNEVICTABLE_PGS_SCANNED, unevictable_pgs_scanned) +REG_set(UNEVICTABLE_PGS_STRANDED, unevictable_pgs_stranded) +REG_set(WORKINGSET_ACTIVATE, workingset_activate) +REG_set(WORKINGSET_NODERECLAIM, workingset_nodereclaim) +REG_set(WORKINGSET_NODES, workingset_nodes) +REG_set(WORKINGSET_REFAULT, workingset_refault) +REG_set(WORKINGSET_RESTORE, workingset_restore) +REG_set(ZONE_RECLAIM_FAILED, zone_reclaim_failed) + +HST_set(DELTA_ALLOCSTALL_DMA, allocstall_dma) +HST_set(DELTA_ALLOCSTALL_DMA32, allocstall_dma32) +HST_set(DELTA_ALLOCSTALL_HIGH, allocstall_high) +HST_set(DELTA_ALLOCSTALL_MOVABLE, allocstall_movable) +HST_set(DELTA_ALLOCSTALL_NORMAL, allocstall_normal) +HST_set(DELTA_BALLOON_DEFLATE, balloon_deflate) +HST_set(DELTA_BALLOON_INFLATE, balloon_inflate) +HST_set(DELTA_BALLOON_MIGRATE, balloon_migrate) +HST_set(DELTA_COMPACT_DAEMON_FREE_SCANNED, compact_daemon_free_scanned) +HST_set(DELTA_COMPACT_DAEMON_MIGRATE_SCANNED, compact_daemon_migrate_scanned) +HST_set(DELTA_COMPACT_DAEMON_WAKE, compact_daemon_wake) +HST_set(DELTA_COMPACT_FAIL, compact_fail) +HST_set(DELTA_COMPACT_FREE_SCANNED, compact_free_scanned) +HST_set(DELTA_COMPACT_ISOLATED, compact_isolated) +HST_set(DELTA_COMPACT_MIGRATE_SCANNED, compact_migrate_scanned) +HST_set(DELTA_COMPACT_STALL, compact_stall) +HST_set(DELTA_COMPACT_SUCCESS, compact_success) +HST_set(DELTA_DROP_PAGECACHE, drop_pagecache) +HST_set(DELTA_DROP_SLAB, drop_slab) +HST_set(DELTA_HTLB_BUDDY_ALLOC_FAIL, htlb_buddy_alloc_fail) +HST_set(DELTA_HTLB_BUDDY_ALLOC_SUCCESS, htlb_buddy_alloc_success) +HST_set(DELTA_KSWAPD_HIGH_WMARK_HIT_QUICKLY, kswapd_high_wmark_hit_quickly) +HST_set(DELTA_KSWAPD_INODESTEAL, kswapd_inodesteal) +HST_set(DELTA_KSWAPD_LOW_WMARK_HIT_QUICKLY, kswapd_low_wmark_hit_quickly) +HST_set(DELTA_NR_ACTIVE_ANON, nr_active_anon) +HST_set(DELTA_NR_ACTIVE_FILE, nr_active_file) +HST_set(DELTA_NR_ANON_PAGES, nr_anon_pages) +HST_set(DELTA_NR_ANON_TRANSPARENT_HUGEPAGES, nr_anon_transparent_hugepages) +HST_set(DELTA_NR_BOUNCE, nr_bounce) +HST_set(DELTA_NR_DIRTIED, nr_dirtied) +HST_set(DELTA_NR_DIRTY, nr_dirty) +HST_set(DELTA_NR_DIRTY_BACKGROUND_THRESHOLD, nr_dirty_background_threshold) +HST_set(DELTA_NR_DIRTY_THRESHOLD, nr_dirty_threshold) +HST_set(DELTA_NR_FILE_HUGEPAGES, nr_file_hugepages) +HST_set(DELTA_NR_FILE_PAGES, nr_file_pages) +HST_set(DELTA_NR_FILE_PMDMAPPED, nr_file_pmdmapped) +HST_set(DELTA_NR_FOLL_PIN_ACQUIRED, nr_foll_pin_acquired) +HST_set(DELTA_NR_FOLL_PIN_RELEASED, nr_foll_pin_released) +HST_set(DELTA_NR_FREE_CMA, nr_free_cma) +HST_set(DELTA_NR_FREE_PAGES, nr_free_pages) +HST_set(DELTA_NR_INACTIVE_ANON, nr_inactive_anon) +HST_set(DELTA_NR_INACTIVE_FILE, nr_inactive_file) +HST_set(DELTA_NR_ISOLATED_ANON, nr_isolated_anon) +HST_set(DELTA_NR_ISOLATED_FILE, nr_isolated_file) +HST_set(DELTA_NR_KERNEL_MISC_RECLAIMABLE, nr_kernel_misc_reclaimable) +HST_set(DELTA_NR_KERNEL_STACK, nr_kernel_stack) +HST_set(DELTA_NR_MAPPED, nr_mapped) +HST_set(DELTA_NR_MLOCK, nr_mlock) +HST_set(DELTA_NR_PAGE_TABLE_PAGES, nr_page_table_pages) +HST_set(DELTA_NR_SHADOW_CALL_STACK, nr_shadow_call_stack) +HST_set(DELTA_NR_SHMEM, nr_shmem) +HST_set(DELTA_NR_SHMEM_HUGEPAGES, nr_shmem_hugepages) +HST_set(DELTA_NR_SHMEM_PMDMAPPED, nr_shmem_pmdmapped) +HST_set(DELTA_NR_SLAB_RECLAIMABLE, nr_slab_reclaimable) +HST_set(DELTA_NR_SLAB_UNRECLAIMABLE, nr_slab_unreclaimable) +HST_set(DELTA_NR_UNEVICTABLE, nr_unevictable) +HST_set(DELTA_NR_UNSTABLE, nr_unstable) +HST_set(DELTA_NR_VMSCAN_IMMEDIATE_RECLAIM, nr_vmscan_immediate_reclaim) +HST_set(DELTA_NR_VMSCAN_WRITE, nr_vmscan_write) +HST_set(DELTA_NR_WRITEBACK, nr_writeback) +HST_set(DELTA_NR_WRITEBACK_TEMP, nr_writeback_temp) +HST_set(DELTA_NR_WRITTEN, nr_written) +HST_set(DELTA_NR_ZONE_ACTIVE_ANON, nr_zone_active_anon) +HST_set(DELTA_NR_ZONE_ACTIVE_FILE, nr_zone_active_file) +HST_set(DELTA_NR_ZONE_INACTIVE_ANON, nr_zone_inactive_anon) +HST_set(DELTA_NR_ZONE_INACTIVE_FILE, nr_zone_inactive_file) +HST_set(DELTA_NR_ZONE_UNEVICTABLE, nr_zone_unevictable) +HST_set(DELTA_NR_ZONE_WRITE_PENDING, nr_zone_write_pending) +HST_set(DELTA_NR_ZSPAGES, nr_zspages) +HST_set(DELTA_NUMA_FOREIGN, numa_foreign) +HST_set(DELTA_NUMA_HINT_FAULTS, numa_hint_faults) +HST_set(DELTA_NUMA_HINT_FAULTS_LOCAL, numa_hint_faults_local) +HST_set(DELTA_NUMA_HIT, numa_hit) +HST_set(DELTA_NUMA_HUGE_PTE_UPDATES, numa_huge_pte_updates) +HST_set(DELTA_NUMA_INTERLEAVE, numa_interleave) +HST_set(DELTA_NUMA_LOCAL, numa_local) +HST_set(DELTA_NUMA_MISS, numa_miss) +HST_set(DELTA_NUMA_OTHER, numa_other) +HST_set(DELTA_NUMA_PAGES_MIGRATED, numa_pages_migrated) +HST_set(DELTA_NUMA_PTE_UPDATES, numa_pte_updates) +HST_set(DELTA_OOM_KILL, oom_kill) +HST_set(DELTA_PAGEOUTRUN, pageoutrun) +HST_set(DELTA_PGACTIVATE, pgactivate) +HST_set(DELTA_PGALLOC_DMA, pgalloc_dma) +HST_set(DELTA_PGALLOC_DMA32, pgalloc_dma32) +HST_set(DELTA_PGALLOC_HIGH, pgalloc_high) +HST_set(DELTA_PGALLOC_MOVABLE, pgalloc_movable) +HST_set(DELTA_PGALLOC_NORMAL, pgalloc_normal) +HST_set(DELTA_PGDEACTIVATE, pgdeactivate) +HST_set(DELTA_PGFAULT, pgfault) +HST_set(DELTA_PGFREE, pgfree) +HST_set(DELTA_PGINODESTEAL, pginodesteal) +HST_set(DELTA_PGLAZYFREE, pglazyfree) +HST_set(DELTA_PGLAZYFREED, pglazyfreed) +HST_set(DELTA_PGMAJFAULT, pgmajfault) +HST_set(DELTA_PGMIGRATE_FAIL, pgmigrate_fail) +HST_set(DELTA_PGMIGRATE_SUCCESS, pgmigrate_success) +HST_set(DELTA_PGPGIN, pgpgin) +HST_set(DELTA_PGPGOUT, pgpgout) +HST_set(DELTA_PGREFILL, pgrefill) +HST_set(DELTA_PGROTATED, pgrotated) +HST_set(DELTA_PGSCAN_ANON, pgscan_anon) +HST_set(DELTA_PGSCAN_DIRECT, pgscan_direct) +HST_set(DELTA_PGSCAN_DIRECT_THROTTLE, pgscan_direct_throttle) +HST_set(DELTA_PGSCAN_FILE, pgscan_file) +HST_set(DELTA_PGSCAN_KSWAPD, pgscan_kswapd) +HST_set(DELTA_PGSKIP_DMA, pgskip_dma) +HST_set(DELTA_PGSKIP_DMA32, pgskip_dma32) +HST_set(DELTA_PGSKIP_HIGH, pgskip_high) +HST_set(DELTA_PGSKIP_MOVABLE, pgskip_movable) +HST_set(DELTA_PGSKIP_NORMAL, pgskip_normal) +HST_set(DELTA_PGSTEAL_ANON, pgsteal_anon) +HST_set(DELTA_PGSTEAL_DIRECT, pgsteal_direct) +HST_set(DELTA_PGSTEAL_FILE, pgsteal_file) +HST_set(DELTA_PGSTEAL_KSWAPD, pgsteal_kswapd) +HST_set(DELTA_PSWPIN, pswpin) +HST_set(DELTA_PSWPOUT, pswpout) +HST_set(DELTA_SLABS_SCANNED, slabs_scanned) +HST_set(DELTA_SWAP_RA, swap_ra) +HST_set(DELTA_SWAP_RA_HIT, swap_ra_hit) +HST_set(DELTA_THP_COLLAPSE_ALLOC, thp_collapse_alloc) +HST_set(DELTA_THP_COLLAPSE_ALLOC_FAILED, thp_collapse_alloc_failed) +HST_set(DELTA_THP_DEFERRED_SPLIT_PAGE, thp_deferred_split_page) +HST_set(DELTA_THP_FAULT_ALLOC, thp_fault_alloc) +HST_set(DELTA_THP_FAULT_FALLBACK, thp_fault_fallback) +HST_set(DELTA_THP_FAULT_FALLBACK_CHARGE, thp_fault_fallback_charge) +HST_set(DELTA_THP_FILE_ALLOC, thp_file_alloc) +HST_set(DELTA_THP_FILE_FALLBACK, thp_file_fallback) +HST_set(DELTA_THP_FILE_FALLBACK_CHARGE, thp_file_fallback_charge) +HST_set(DELTA_THP_FILE_MAPPED, thp_file_mapped) +HST_set(DELTA_THP_SPLIT_PAGE, thp_split_page) +HST_set(DELTA_THP_SPLIT_PAGE_FAILED, thp_split_page_failed) +HST_set(DELTA_THP_SPLIT_PMD, thp_split_pmd) +HST_set(DELTA_THP_SPLIT_PUD, thp_split_pud) +HST_set(DELTA_THP_SWPOUT, thp_swpout) +HST_set(DELTA_THP_SWPOUT_FALLBACK, thp_swpout_fallback) +HST_set(DELTA_THP_ZERO_PAGE_ALLOC, thp_zero_page_alloc) +HST_set(DELTA_THP_ZERO_PAGE_ALLOC_FAILED, thp_zero_page_alloc_failed) +HST_set(DELTA_UNEVICTABLE_PGS_CLEARED, unevictable_pgs_cleared) +HST_set(DELTA_UNEVICTABLE_PGS_CULLED, unevictable_pgs_culled) +HST_set(DELTA_UNEVICTABLE_PGS_MLOCKED, unevictable_pgs_mlocked) +HST_set(DELTA_UNEVICTABLE_PGS_MUNLOCKED, unevictable_pgs_munlocked) +HST_set(DELTA_UNEVICTABLE_PGS_RESCUED, unevictable_pgs_rescued) +HST_set(DELTA_UNEVICTABLE_PGS_SCANNED, unevictable_pgs_scanned) +HST_set(DELTA_UNEVICTABLE_PGS_STRANDED, unevictable_pgs_stranded) +HST_set(DELTA_WORKINGSET_ACTIVATE, workingset_activate) +HST_set(DELTA_WORKINGSET_NODERECLAIM, workingset_nodereclaim) +HST_set(DELTA_WORKINGSET_NODES, workingset_nodes) +HST_set(DELTA_WORKINGSET_REFAULT, workingset_refault) +HST_set(DELTA_WORKINGSET_RESTORE, workingset_restore) +HST_set(DELTA_ZONE_RECLAIM_FAILED, zone_reclaim_failed) + +#undef setDECL +#undef REG_set +#undef HST_set + + +// ___ Controlling Table |||||||||||||||||||||||||||||||||||||||||||||||||||||| + +typedef void (*SET_t)(struct vmstat_result *, struct vmstat_hist *); +#ifdef ITEMTABLE_DEBUG +#define RS(e) (SET_t)setNAME(e), VMSTAT_ ## e, STRINGIFY(VMSTAT_ ## e) +#else +#define RS(e) (SET_t)setNAME(e) +#endif + +#define TS(t) STRINGIFY(t) +#define TS_noop "" + + /* + * Need it be said? + * This table must be kept in the exact same order as + * those 'enum vmstat_item' guys ! */ +static struct { + SET_t setsfunc; // the actual result setting routine +#ifdef ITEMTABLE_DEBUG + int enumnumb; // enumerator (must match position!) + char *enum2str; // enumerator name as a char* string +#endif + char *type2str; // the result type as a string value +} Item_table[] = { +/* setsfunc type2str + ----------------------------------------- ---------- */ + { RS(noop), TS_noop }, + { RS(extra), TS_noop }, + + { RS(ALLOCSTALL_DMA), TS(ul_int) }, + { RS(ALLOCSTALL_DMA32), TS(ul_int) }, + { RS(ALLOCSTALL_HIGH), TS(ul_int) }, + { RS(ALLOCSTALL_MOVABLE), TS(ul_int) }, + { RS(ALLOCSTALL_NORMAL), TS(ul_int) }, + { RS(BALLOON_DEFLATE), TS(ul_int) }, + { RS(BALLOON_INFLATE), TS(ul_int) }, + { RS(BALLOON_MIGRATE), TS(ul_int) }, + { RS(COMPACT_DAEMON_FREE_SCANNED), TS(ul_int) }, + { RS(COMPACT_DAEMON_MIGRATE_SCANNED), TS(ul_int) }, + { RS(COMPACT_DAEMON_WAKE), TS(ul_int) }, + { RS(COMPACT_FAIL), TS(ul_int) }, + { RS(COMPACT_FREE_SCANNED), TS(ul_int) }, + { RS(COMPACT_ISOLATED), TS(ul_int) }, + { RS(COMPACT_MIGRATE_SCANNED), TS(ul_int) }, + { RS(COMPACT_STALL), TS(ul_int) }, + { RS(COMPACT_SUCCESS), TS(ul_int) }, + { RS(DROP_PAGECACHE), TS(ul_int) }, + { RS(DROP_SLAB), TS(ul_int) }, + { RS(HTLB_BUDDY_ALLOC_FAIL), TS(ul_int) }, + { RS(HTLB_BUDDY_ALLOC_SUCCESS), TS(ul_int) }, + { RS(KSWAPD_HIGH_WMARK_HIT_QUICKLY), TS(ul_int) }, + { RS(KSWAPD_INODESTEAL), TS(ul_int) }, + { RS(KSWAPD_LOW_WMARK_HIT_QUICKLY), TS(ul_int) }, + { RS(NR_ACTIVE_ANON), TS(ul_int) }, + { RS(NR_ACTIVE_FILE), TS(ul_int) }, + { RS(NR_ANON_PAGES), TS(ul_int) }, + { RS(NR_ANON_TRANSPARENT_HUGEPAGES), TS(ul_int) }, + { RS(NR_BOUNCE), TS(ul_int) }, + { RS(NR_DIRTIED), TS(ul_int) }, + { RS(NR_DIRTY), TS(ul_int) }, + { RS(NR_DIRTY_BACKGROUND_THRESHOLD), TS(ul_int) }, + { RS(NR_DIRTY_THRESHOLD), TS(ul_int) }, + { RS(NR_FILE_HUGEPAGES), TS(ul_int) }, + { RS(NR_FILE_PAGES), TS(ul_int) }, + { RS(NR_FILE_PMDMAPPED), TS(ul_int) }, + { RS(NR_FOLL_PIN_ACQUIRED), TS(ul_int) }, + { RS(NR_FOLL_PIN_RELEASED), TS(ul_int) }, + { RS(NR_FREE_CMA), TS(ul_int) }, + { RS(NR_FREE_PAGES), TS(ul_int) }, + { RS(NR_INACTIVE_ANON), TS(ul_int) }, + { RS(NR_INACTIVE_FILE), TS(ul_int) }, + { RS(NR_ISOLATED_ANON), TS(ul_int) }, + { RS(NR_ISOLATED_FILE), TS(ul_int) }, + { RS(NR_KERNEL_MISC_RECLAIMABLE), TS(ul_int) }, + { RS(NR_KERNEL_STACK), TS(ul_int) }, + { RS(NR_MAPPED), TS(ul_int) }, + { RS(NR_MLOCK), TS(ul_int) }, + { RS(NR_PAGE_TABLE_PAGES), TS(ul_int) }, + { RS(NR_SHADOW_CALL_STACK), TS(ul_int) }, + { RS(NR_SHMEM), TS(ul_int) }, + { RS(NR_SHMEM_HUGEPAGES), TS(ul_int) }, + { RS(NR_SHMEM_PMDMAPPED), TS(ul_int) }, + { RS(NR_SLAB_RECLAIMABLE), TS(ul_int) }, + { RS(NR_SLAB_UNRECLAIMABLE), TS(ul_int) }, + { RS(NR_UNEVICTABLE), TS(ul_int) }, + { RS(NR_UNSTABLE), TS(ul_int) }, + { RS(NR_VMSCAN_IMMEDIATE_RECLAIM), TS(ul_int) }, + { RS(NR_VMSCAN_WRITE), TS(ul_int) }, + { RS(NR_WRITEBACK), TS(ul_int) }, + { RS(NR_WRITEBACK_TEMP), TS(ul_int) }, + { RS(NR_WRITTEN), TS(ul_int) }, + { RS(NR_ZONE_ACTIVE_ANON), TS(ul_int) }, + { RS(NR_ZONE_ACTIVE_FILE), TS(ul_int) }, + { RS(NR_ZONE_INACTIVE_ANON), TS(ul_int) }, + { RS(NR_ZONE_INACTIVE_FILE), TS(ul_int) }, + { RS(NR_ZONE_UNEVICTABLE), TS(ul_int) }, + { RS(NR_ZONE_WRITE_PENDING), TS(ul_int) }, + { RS(NR_ZSPAGES), TS(ul_int) }, + { RS(NUMA_FOREIGN), TS(ul_int) }, + { RS(NUMA_HINT_FAULTS), TS(ul_int) }, + { RS(NUMA_HINT_FAULTS_LOCAL), TS(ul_int) }, + { RS(NUMA_HIT), TS(ul_int) }, + { RS(NUMA_HUGE_PTE_UPDATES), TS(ul_int) }, + { RS(NUMA_INTERLEAVE), TS(ul_int) }, + { RS(NUMA_LOCAL), TS(ul_int) }, + { RS(NUMA_MISS), TS(ul_int) }, + { RS(NUMA_OTHER), TS(ul_int) }, + { RS(NUMA_PAGES_MIGRATED), TS(ul_int) }, + { RS(NUMA_PTE_UPDATES), TS(ul_int) }, + { RS(OOM_KILL), TS(ul_int) }, + { RS(PAGEOUTRUN), TS(ul_int) }, + { RS(PGACTIVATE), TS(ul_int) }, + { RS(PGALLOC_DMA), TS(ul_int) }, + { RS(PGALLOC_DMA32), TS(ul_int) }, + { RS(PGALLOC_HIGH), TS(ul_int) }, + { RS(PGALLOC_MOVABLE), TS(ul_int) }, + { RS(PGALLOC_NORMAL), TS(ul_int) }, + { RS(PGDEACTIVATE), TS(ul_int) }, + { RS(PGFAULT), TS(ul_int) }, + { RS(PGFREE), TS(ul_int) }, + { RS(PGINODESTEAL), TS(ul_int) }, + { RS(PGLAZYFREE), TS(ul_int) }, + { RS(PGLAZYFREED), TS(ul_int) }, + { RS(PGMAJFAULT), TS(ul_int) }, + { RS(PGMIGRATE_FAIL), TS(ul_int) }, + { RS(PGMIGRATE_SUCCESS), TS(ul_int) }, + { RS(PGPGIN), TS(ul_int) }, + { RS(PGPGOUT), TS(ul_int) }, + { RS(PGREFILL), TS(ul_int) }, + { RS(PGROTATED), TS(ul_int) }, + { RS(PGSCAN_ANON), TS(ul_int) }, + { RS(PGSCAN_DIRECT), TS(ul_int) }, + { RS(PGSCAN_DIRECT_THROTTLE), TS(ul_int) }, + { RS(PGSCAN_FILE), TS(ul_int) }, + { RS(PGSCAN_KSWAPD), TS(ul_int) }, + { RS(PGSKIP_DMA), TS(ul_int) }, + { RS(PGSKIP_DMA32), TS(ul_int) }, + { RS(PGSKIP_HIGH), TS(ul_int) }, + { RS(PGSKIP_MOVABLE), TS(ul_int) }, + { RS(PGSKIP_NORMAL), TS(ul_int) }, + { RS(PGSTEAL_ANON), TS(ul_int) }, + { RS(PGSTEAL_DIRECT), TS(ul_int) }, + { RS(PGSTEAL_FILE), TS(ul_int) }, + { RS(PGSTEAL_KSWAPD), TS(ul_int) }, + { RS(PSWPIN), TS(ul_int) }, + { RS(PSWPOUT), TS(ul_int) }, + { RS(SLABS_SCANNED), TS(ul_int) }, + { RS(SWAP_RA), TS(ul_int) }, + { RS(SWAP_RA_HIT), TS(ul_int) }, + { RS(THP_COLLAPSE_ALLOC), TS(ul_int) }, + { RS(THP_COLLAPSE_ALLOC_FAILED), TS(ul_int) }, + { RS(THP_DEFERRED_SPLIT_PAGE), TS(ul_int) }, + { RS(THP_FAULT_ALLOC), TS(ul_int) }, + { RS(THP_FAULT_FALLBACK), TS(ul_int) }, + { RS(THP_FAULT_FALLBACK_CHARGE), TS(ul_int) }, + { RS(THP_FILE_ALLOC), TS(ul_int) }, + { RS(THP_FILE_FALLBACK), TS(ul_int) }, + { RS(THP_FILE_FALLBACK_CHARGE), TS(ul_int) }, + { RS(THP_FILE_MAPPED), TS(ul_int) }, + { RS(THP_SPLIT_PAGE), TS(ul_int) }, + { RS(THP_SPLIT_PAGE_FAILED), TS(ul_int) }, + { RS(THP_SPLIT_PMD), TS(ul_int) }, + { RS(THP_SPLIT_PUD), TS(ul_int) }, + { RS(THP_SWPOUT), TS(ul_int) }, + { RS(THP_SWPOUT_FALLBACK), TS(ul_int) }, + { RS(THP_ZERO_PAGE_ALLOC), TS(ul_int) }, + { RS(THP_ZERO_PAGE_ALLOC_FAILED), TS(ul_int) }, + { RS(UNEVICTABLE_PGS_CLEARED), TS(ul_int) }, + { RS(UNEVICTABLE_PGS_CULLED), TS(ul_int) }, + { RS(UNEVICTABLE_PGS_MLOCKED), TS(ul_int) }, + { RS(UNEVICTABLE_PGS_MUNLOCKED), TS(ul_int) }, + { RS(UNEVICTABLE_PGS_RESCUED), TS(ul_int) }, + { RS(UNEVICTABLE_PGS_SCANNED), TS(ul_int) }, + { RS(UNEVICTABLE_PGS_STRANDED), TS(ul_int) }, + { RS(WORKINGSET_ACTIVATE), TS(ul_int) }, + { RS(WORKINGSET_NODERECLAIM), TS(ul_int) }, + { RS(WORKINGSET_NODES), TS(ul_int) }, + { RS(WORKINGSET_REFAULT), TS(ul_int) }, + { RS(WORKINGSET_RESTORE), TS(ul_int) }, + { RS(ZONE_RECLAIM_FAILED), TS(ul_int) }, + + { RS(DELTA_ALLOCSTALL_DMA), TS(sl_int) }, + { RS(DELTA_ALLOCSTALL_DMA32), TS(sl_int) }, + { RS(DELTA_ALLOCSTALL_HIGH), TS(sl_int) }, + { RS(DELTA_ALLOCSTALL_MOVABLE), TS(sl_int) }, + { RS(DELTA_ALLOCSTALL_NORMAL), TS(sl_int) }, + { RS(DELTA_BALLOON_DEFLATE), TS(sl_int) }, + { RS(DELTA_BALLOON_INFLATE), TS(sl_int) }, + { RS(DELTA_BALLOON_MIGRATE), TS(sl_int) }, + { RS(DELTA_COMPACT_DAEMON_FREE_SCANNED), TS(sl_int) }, + { RS(DELTA_COMPACT_DAEMON_MIGRATE_SCANNED), TS(sl_int) }, + { RS(DELTA_COMPACT_DAEMON_WAKE), TS(sl_int) }, + { RS(DELTA_COMPACT_FAIL), TS(sl_int) }, + { RS(DELTA_COMPACT_FREE_SCANNED), TS(sl_int) }, + { RS(DELTA_COMPACT_ISOLATED), TS(sl_int) }, + { RS(DELTA_COMPACT_MIGRATE_SCANNED), TS(sl_int) }, + { RS(DELTA_COMPACT_STALL), TS(sl_int) }, + { RS(DELTA_COMPACT_SUCCESS), TS(sl_int) }, + { RS(DELTA_DROP_PAGECACHE), TS(sl_int) }, + { RS(DELTA_DROP_SLAB), TS(sl_int) }, + { RS(DELTA_HTLB_BUDDY_ALLOC_FAIL), TS(sl_int) }, + { RS(DELTA_HTLB_BUDDY_ALLOC_SUCCESS), TS(sl_int) }, + { RS(DELTA_KSWAPD_HIGH_WMARK_HIT_QUICKLY), TS(sl_int) }, + { RS(DELTA_KSWAPD_INODESTEAL), TS(sl_int) }, + { RS(DELTA_KSWAPD_LOW_WMARK_HIT_QUICKLY), TS(sl_int) }, + { RS(DELTA_NR_ACTIVE_ANON), TS(sl_int) }, + { RS(DELTA_NR_ACTIVE_FILE), TS(sl_int) }, + { RS(DELTA_NR_ANON_PAGES), TS(sl_int) }, + { RS(DELTA_NR_ANON_TRANSPARENT_HUGEPAGES), TS(sl_int) }, + { RS(DELTA_NR_BOUNCE), TS(sl_int) }, + { RS(DELTA_NR_DIRTIED), TS(sl_int) }, + { RS(DELTA_NR_DIRTY), TS(sl_int) }, + { RS(DELTA_NR_DIRTY_BACKGROUND_THRESHOLD), TS(sl_int) }, + { RS(DELTA_NR_DIRTY_THRESHOLD), TS(sl_int) }, + { RS(DELTA_NR_FILE_HUGEPAGES), TS(sl_int) }, + { RS(DELTA_NR_FILE_PAGES), TS(sl_int) }, + { RS(DELTA_NR_FILE_PMDMAPPED), TS(sl_int) }, + { RS(DELTA_NR_FOLL_PIN_ACQUIRED), TS(sl_int) }, + { RS(DELTA_NR_FOLL_PIN_RELEASED), TS(sl_int) }, + { RS(DELTA_NR_FREE_CMA), TS(sl_int) }, + { RS(DELTA_NR_FREE_PAGES), TS(sl_int) }, + { RS(DELTA_NR_INACTIVE_ANON), TS(sl_int) }, + { RS(DELTA_NR_INACTIVE_FILE), TS(sl_int) }, + { RS(DELTA_NR_ISOLATED_ANON), TS(sl_int) }, + { RS(DELTA_NR_ISOLATED_FILE), TS(sl_int) }, + { RS(DELTA_NR_KERNEL_MISC_RECLAIMABLE), TS(sl_int) }, + { RS(DELTA_NR_KERNEL_STACK), TS(sl_int) }, + { RS(DELTA_NR_MAPPED), TS(sl_int) }, + { RS(DELTA_NR_MLOCK), TS(sl_int) }, + { RS(DELTA_NR_PAGE_TABLE_PAGES), TS(sl_int) }, + { RS(DELTA_NR_SHADOW_CALL_STACK), TS(sl_int) }, + { RS(DELTA_NR_SHMEM), TS(sl_int) }, + { RS(DELTA_NR_SHMEM_HUGEPAGES), TS(sl_int) }, + { RS(DELTA_NR_SHMEM_PMDMAPPED), TS(sl_int) }, + { RS(DELTA_NR_SLAB_RECLAIMABLE), TS(sl_int) }, + { RS(DELTA_NR_SLAB_UNRECLAIMABLE), TS(sl_int) }, + { RS(DELTA_NR_UNEVICTABLE), TS(sl_int) }, + { RS(DELTA_NR_UNSTABLE), TS(sl_int) }, + { RS(DELTA_NR_VMSCAN_IMMEDIATE_RECLAIM), TS(sl_int) }, + { RS(DELTA_NR_VMSCAN_WRITE), TS(sl_int) }, + { RS(DELTA_NR_WRITEBACK), TS(sl_int) }, + { RS(DELTA_NR_WRITEBACK_TEMP), TS(sl_int) }, + { RS(DELTA_NR_WRITTEN), TS(sl_int) }, + { RS(DELTA_NR_ZONE_ACTIVE_ANON), TS(sl_int) }, + { RS(DELTA_NR_ZONE_ACTIVE_FILE), TS(sl_int) }, + { RS(DELTA_NR_ZONE_INACTIVE_ANON), TS(sl_int) }, + { RS(DELTA_NR_ZONE_INACTIVE_FILE), TS(sl_int) }, + { RS(DELTA_NR_ZONE_UNEVICTABLE), TS(sl_int) }, + { RS(DELTA_NR_ZONE_WRITE_PENDING), TS(sl_int) }, + { RS(DELTA_NR_ZSPAGES), TS(sl_int) }, + { RS(DELTA_NUMA_FOREIGN), TS(sl_int) }, + { RS(DELTA_NUMA_HINT_FAULTS), TS(sl_int) }, + { RS(DELTA_NUMA_HINT_FAULTS_LOCAL), TS(sl_int) }, + { RS(DELTA_NUMA_HIT), TS(sl_int) }, + { RS(DELTA_NUMA_HUGE_PTE_UPDATES), TS(sl_int) }, + { RS(DELTA_NUMA_INTERLEAVE), TS(sl_int) }, + { RS(DELTA_NUMA_LOCAL), TS(sl_int) }, + { RS(DELTA_NUMA_MISS), TS(sl_int) }, + { RS(DELTA_NUMA_OTHER), TS(sl_int) }, + { RS(DELTA_NUMA_PAGES_MIGRATED), TS(sl_int) }, + { RS(DELTA_NUMA_PTE_UPDATES), TS(sl_int) }, + { RS(DELTA_OOM_KILL), TS(sl_int) }, + { RS(DELTA_PAGEOUTRUN), TS(sl_int) }, + { RS(DELTA_PGACTIVATE), TS(sl_int) }, + { RS(DELTA_PGALLOC_DMA), TS(sl_int) }, + { RS(DELTA_PGALLOC_DMA32), TS(sl_int) }, + { RS(DELTA_PGALLOC_HIGH), TS(sl_int) }, + { RS(DELTA_PGALLOC_MOVABLE), TS(sl_int) }, + { RS(DELTA_PGALLOC_NORMAL), TS(sl_int) }, + { RS(DELTA_PGDEACTIVATE), TS(sl_int) }, + { RS(DELTA_PGFAULT), TS(sl_int) }, + { RS(DELTA_PGFREE), TS(sl_int) }, + { RS(DELTA_PGINODESTEAL), TS(sl_int) }, + { RS(DELTA_PGLAZYFREE), TS(sl_int) }, + { RS(DELTA_PGLAZYFREED), TS(sl_int) }, + { RS(DELTA_PGMAJFAULT), TS(sl_int) }, + { RS(DELTA_PGMIGRATE_FAIL), TS(sl_int) }, + { RS(DELTA_PGMIGRATE_SUCCESS), TS(sl_int) }, + { RS(DELTA_PGPGIN), TS(sl_int) }, + { RS(DELTA_PGPGOUT), TS(sl_int) }, + { RS(DELTA_PGREFILL), TS(sl_int) }, + { RS(DELTA_PGROTATED), TS(sl_int) }, + { RS(DELTA_PGSCAN_ANON), TS(sl_int) }, + { RS(DELTA_PGSCAN_DIRECT), TS(sl_int) }, + { RS(DELTA_PGSCAN_DIRECT_THROTTLE), TS(sl_int) }, + { RS(DELTA_PGSCAN_FILE), TS(sl_int) }, + { RS(DELTA_PGSCAN_KSWAPD), TS(sl_int) }, + { RS(DELTA_PGSKIP_DMA), TS(sl_int) }, + { RS(DELTA_PGSKIP_DMA32), TS(sl_int) }, + { RS(DELTA_PGSKIP_HIGH), TS(sl_int) }, + { RS(DELTA_PGSKIP_MOVABLE), TS(sl_int) }, + { RS(DELTA_PGSKIP_NORMAL), TS(sl_int) }, + { RS(DELTA_PGSTEAL_ANON), TS(sl_int) }, + { RS(DELTA_PGSTEAL_DIRECT), TS(sl_int) }, + { RS(DELTA_PGSTEAL_FILE), TS(sl_int) }, + { RS(DELTA_PGSTEAL_KSWAPD), TS(sl_int) }, + { RS(DELTA_PSWPIN), TS(sl_int) }, + { RS(DELTA_PSWPOUT), TS(sl_int) }, + { RS(DELTA_SLABS_SCANNED), TS(sl_int) }, + { RS(DELTA_SWAP_RA), TS(sl_int) }, + { RS(DELTA_SWAP_RA_HIT), TS(sl_int) }, + { RS(DELTA_THP_COLLAPSE_ALLOC), TS(sl_int) }, + { RS(DELTA_THP_COLLAPSE_ALLOC_FAILED), TS(sl_int) }, + { RS(DELTA_THP_DEFERRED_SPLIT_PAGE), TS(sl_int) }, + { RS(DELTA_THP_FAULT_ALLOC), TS(sl_int) }, + { RS(DELTA_THP_FAULT_FALLBACK), TS(sl_int) }, + { RS(DELTA_THP_FAULT_FALLBACK_CHARGE), TS(sl_int) }, + { RS(DELTA_THP_FILE_ALLOC), TS(sl_int) }, + { RS(DELTA_THP_FILE_FALLBACK), TS(sl_int) }, + { RS(DELTA_THP_FILE_FALLBACK_CHARGE), TS(sl_int) }, + { RS(DELTA_THP_FILE_MAPPED), TS(sl_int) }, + { RS(DELTA_THP_SPLIT_PAGE), TS(sl_int) }, + { RS(DELTA_THP_SPLIT_PAGE_FAILED), TS(sl_int) }, + { RS(DELTA_THP_SPLIT_PMD), TS(sl_int) }, + { RS(DELTA_THP_SPLIT_PUD), TS(sl_int) }, + { RS(DELTA_THP_SWPOUT), TS(sl_int) }, + { RS(DELTA_THP_SWPOUT_FALLBACK), TS(sl_int) }, + { RS(DELTA_THP_ZERO_PAGE_ALLOC), TS(sl_int) }, + { RS(DELTA_THP_ZERO_PAGE_ALLOC_FAILED), TS(sl_int) }, + { RS(DELTA_UNEVICTABLE_PGS_CLEARED), TS(sl_int) }, + { RS(DELTA_UNEVICTABLE_PGS_CULLED), TS(sl_int) }, + { RS(DELTA_UNEVICTABLE_PGS_MLOCKED), TS(sl_int) }, + { RS(DELTA_UNEVICTABLE_PGS_MUNLOCKED), TS(sl_int) }, + { RS(DELTA_UNEVICTABLE_PGS_RESCUED), TS(sl_int) }, + { RS(DELTA_UNEVICTABLE_PGS_SCANNED), TS(sl_int) }, + { RS(DELTA_UNEVICTABLE_PGS_STRANDED), TS(sl_int) }, + { RS(DELTA_WORKINGSET_ACTIVATE), TS(sl_int) }, + { RS(DELTA_WORKINGSET_NODERECLAIM), TS(sl_int) }, + { RS(DELTA_WORKINGSET_NODES), TS(sl_int) }, + { RS(DELTA_WORKINGSET_REFAULT), TS(sl_int) }, + { RS(DELTA_WORKINGSET_RESTORE), TS(sl_int) }, + { RS(DELTA_ZONE_RECLAIM_FAILED), TS(sl_int) }, +}; + + /* please note, + * this enum MUST be 1 greater than the highest value of any enum */ +enum vmstat_item VMSTAT_logical_end = MAXTABLE(Item_table); + +#undef setNAME +#undef RS + + +// ___ Private Functions |||||||||||||||||||||||||||||||||||||||||||||||||||||| + +static inline void vmstat_assign_results ( + struct vmstat_stack *stack, + struct vmstat_hist *hist) +{ + struct vmstat_result *this = stack->head; + + for (;;) { + enum vmstat_item item = this->item; + if (item >= VMSTAT_logical_end) + break; + Item_table[item].setsfunc(this, hist); + ++this; + } + return; +} // end: vmstat_assign_results + + +static void vmstat_extents_free_all ( + struct vmstat_info *info) +{ + while (info->extents) { + struct stacks_extent *p = info->extents; + info->extents = info->extents->next; + free(p); + }; +} // end: vmstat_extents_free_all + + +static inline struct vmstat_result *vmstat_itemize_stack ( + struct vmstat_result *p, + int depth, + enum vmstat_item *items) +{ + struct vmstat_result *p_sav = p; + int i; + + for (i = 0; i < depth; i++) { + p->item = items[i]; + ++p; + } + return p_sav; +} // end: vmstat_itemize_stack + + +static inline int vmstat_items_check_failed ( + int numitems, + enum vmstat_item *items) +{ + int i; + + /* if an enum is passed instead of an address of one or more enums, ol' gcc + * will silently convert it to an address (possibly NULL). only clang will + * offer any sort of warning like the following: + * + * warning: incompatible integer to pointer conversion passing 'int' to parameter of type 'enum vmstat_item *' + * my_stack = procps_vmstat_select(info, VMSTAT_noop, num); + * ^~~~~~~~~~~~~~~~ + */ + if (numitems < 1 + || (void *)items < (void *)(unsigned long)(2 * VMSTAT_logical_end)) + return 1; + + for (i = 0; i < numitems; i++) { + // a vmstat_item is currently unsigned, but we'll protect our future + if (items[i] < 0) + return 1; + if (items[i] >= VMSTAT_logical_end) + return 1; + } + + return 0; +} // end: vmstat_items_check_failed + + +static int vmstat_make_hash_failed ( + struct vmstat_info *info) +{ + #define htVAL(f) e.key = STRINGIFY(f); e.data = &info->hist.new. f; \ + if (!hsearch_r(e, ENTER, &ep, &info->hashtab)) return 1; + ENTRY e, *ep; + size_t n; + + n = sizeof(struct vmstat_data) / sizeof(unsigned long); + // we'll follow the hsearch recommendation of an extra 25% + if (!hcreate_r(n + (n / 4), &info->hashtab)) + return 1; + + htVAL(allocstall_dma) + htVAL(allocstall_dma32) + htVAL(allocstall_high) + htVAL(allocstall_movable) + htVAL(allocstall_normal) + htVAL(balloon_deflate) + htVAL(balloon_inflate) + htVAL(balloon_migrate) + htVAL(compact_daemon_free_scanned) + htVAL(compact_daemon_migrate_scanned) + htVAL(compact_daemon_wake) + htVAL(compact_fail) + htVAL(compact_free_scanned) + htVAL(compact_isolated) + htVAL(compact_migrate_scanned) + htVAL(compact_stall) + htVAL(compact_success) + htVAL(drop_pagecache) + htVAL(drop_slab) + htVAL(htlb_buddy_alloc_fail) + htVAL(htlb_buddy_alloc_success) + htVAL(kswapd_high_wmark_hit_quickly) + htVAL(kswapd_inodesteal) + htVAL(kswapd_low_wmark_hit_quickly) + htVAL(nr_active_anon) + htVAL(nr_active_file) + htVAL(nr_anon_pages) + htVAL(nr_anon_transparent_hugepages) + htVAL(nr_bounce) + htVAL(nr_dirtied) + htVAL(nr_dirty) + htVAL(nr_dirty_background_threshold) + htVAL(nr_dirty_threshold) + htVAL(nr_file_hugepages) + htVAL(nr_file_pages) + htVAL(nr_file_pmdmapped) + htVAL(nr_foll_pin_acquired) + htVAL(nr_foll_pin_released) + htVAL(nr_free_cma) + htVAL(nr_free_pages) + htVAL(nr_inactive_anon) + htVAL(nr_inactive_file) + htVAL(nr_isolated_anon) + htVAL(nr_isolated_file) + htVAL(nr_kernel_misc_reclaimable) + htVAL(nr_kernel_stack) + htVAL(nr_mapped) + htVAL(nr_mlock) + htVAL(nr_page_table_pages) + htVAL(nr_shadow_call_stack) + htVAL(nr_shmem) + htVAL(nr_shmem_hugepages) + htVAL(nr_shmem_pmdmapped) + htVAL(nr_slab_reclaimable) + htVAL(nr_slab_unreclaimable) + htVAL(nr_unevictable) + htVAL(nr_unstable) + htVAL(nr_vmscan_immediate_reclaim) + htVAL(nr_vmscan_write) + htVAL(nr_writeback) + htVAL(nr_writeback_temp) + htVAL(nr_written) + htVAL(nr_zone_active_anon) + htVAL(nr_zone_active_file) + htVAL(nr_zone_inactive_anon) + htVAL(nr_zone_inactive_file) + htVAL(nr_zone_unevictable) + htVAL(nr_zone_write_pending) + htVAL(nr_zspages) + htVAL(numa_foreign) + htVAL(numa_hint_faults) + htVAL(numa_hint_faults_local) + htVAL(numa_hit) + htVAL(numa_huge_pte_updates) + htVAL(numa_interleave) + htVAL(numa_local) + htVAL(numa_miss) + htVAL(numa_other) + htVAL(numa_pages_migrated) + htVAL(numa_pte_updates) + htVAL(oom_kill) + htVAL(pageoutrun) + htVAL(pgactivate) + htVAL(pgalloc_dma) + htVAL(pgalloc_dma32) + htVAL(pgalloc_high) + htVAL(pgalloc_movable) + htVAL(pgalloc_normal) + htVAL(pgdeactivate) + htVAL(pgfault) + htVAL(pgfree) + htVAL(pginodesteal) + htVAL(pglazyfree) + htVAL(pglazyfreed) + htVAL(pgmajfault) + htVAL(pgmigrate_fail) + htVAL(pgmigrate_success) + htVAL(pgpgin) + htVAL(pgpgout) + htVAL(pgrefill) + htVAL(pgrotated) + htVAL(pgscan_anon) + htVAL(pgscan_direct) + htVAL(pgscan_direct_throttle) + htVAL(pgscan_file) + htVAL(pgscan_kswapd) + htVAL(pgskip_dma) + htVAL(pgskip_dma32) + htVAL(pgskip_high) + htVAL(pgskip_movable) + htVAL(pgskip_normal) + htVAL(pgsteal_anon) + htVAL(pgsteal_direct) + htVAL(pgsteal_file) + htVAL(pgsteal_kswapd) + htVAL(pswpin) + htVAL(pswpout) + htVAL(slabs_scanned) + htVAL(swap_ra) + htVAL(swap_ra_hit) + htVAL(thp_collapse_alloc) + htVAL(thp_collapse_alloc_failed) + htVAL(thp_deferred_split_page) + htVAL(thp_fault_alloc) + htVAL(thp_fault_fallback) + htVAL(thp_fault_fallback_charge) + htVAL(thp_file_alloc) + htVAL(thp_file_fallback) + htVAL(thp_file_fallback_charge) + htVAL(thp_file_mapped) + htVAL(thp_split_page) + htVAL(thp_split_page_failed) + htVAL(thp_split_pmd) + htVAL(thp_split_pud) + htVAL(thp_swpout) + htVAL(thp_swpout_fallback) + htVAL(thp_zero_page_alloc) + htVAL(thp_zero_page_alloc_failed) + htVAL(unevictable_pgs_cleared) + htVAL(unevictable_pgs_culled) + htVAL(unevictable_pgs_mlocked) + htVAL(unevictable_pgs_munlocked) + htVAL(unevictable_pgs_rescued) + htVAL(unevictable_pgs_scanned) + htVAL(unevictable_pgs_stranded) + htVAL(workingset_activate) + htVAL(workingset_nodereclaim) + htVAL(workingset_nodes) + htVAL(workingset_refault) + htVAL(workingset_restore) + htVAL(zone_reclaim_failed) + + return 0; + #undef htVAL +} // end: vmstat_make_hash_failed + + +/* + * vmstat_read_failed(): + * + * Read the data out of /proc/vmstat putting the information + * into the supplied info structure + */ +static int vmstat_read_failed ( + struct vmstat_info *info) +{ + char buf[VMSTAT_BUFF]; + char *head, *tail; + int size; + unsigned long *valptr; + + // remember history from last time around + memcpy(&info->hist.old, &info->hist.new, sizeof(struct vmstat_data)); + // clear out the soon to be 'current' values + memset(&info->hist.new, 0, sizeof(struct vmstat_data)); + +#ifndef __CYGWIN__ /* /proc/vmstat does not exist */ + if (-1 == info->vmstat_fd + && (-1 == (info->vmstat_fd = open(VMSTAT_FILE, O_RDONLY)))) + return 1; + + if (lseek(info->vmstat_fd, 0L, SEEK_SET) == -1) + return 1; + + for (;;) { + if ((size = read(info->vmstat_fd, buf, sizeof(buf)-1)) < 0) { + if (errno == EINTR || errno == EAGAIN) + continue; + return 1; + } + break; + } + if (size == 0) { + errno = EIO; + return 1; + } + buf[size] = '\0'; + + head = buf; + + for (;;) { + static __thread ENTRY e; // keep coverity off our backs (e.data) + ENTRY *ep; + + if (!(tail = strchr(head, ' '))) + break; + *tail = '\0'; + valptr = NULL; + + e.key = head; + if (hsearch_r(e, FIND, &ep, &info->hashtab)) + valptr = ep->data; + head = tail + 1; + if (valptr) + *valptr = strtoul(head, NULL, 10); + + if (!(tail = strchr(head, '\n'))) + break; + head = tail + 1; + } +#endif /* !__CYGWIN__ */ + return 0; +} // end: vmstat_read_failed + + +/* + * vmstat_stacks_alloc(): + * + * Allocate and initialize one or more stacks each of which is anchored in an + * associated context structure. + * + * All such stacks will have their result structures properly primed with + * 'items', while the result itself will be zeroed. + * + * Returns a stacks_extent struct anchoring the 'heads' of each new stack. + */ +static struct stacks_extent *vmstat_stacks_alloc ( + struct vmstat_info *info, + int maxstacks) +{ + struct stacks_extent *p_blob; + struct vmstat_stack **p_vect; + struct vmstat_stack *p_head; + size_t vect_size, head_size, list_size, blob_size; + void *v_head, *v_list; + int i; + + vect_size = sizeof(void *) * maxstacks; // size of the addr vectors | + vect_size += sizeof(void *); // plus NULL addr delimiter | + head_size = sizeof(struct vmstat_stack); // size of that head struct | + list_size = sizeof(struct vmstat_result)*info->numitems; // any single results stack | + blob_size = sizeof(struct stacks_extent); // the extent anchor itself | + blob_size += vect_size; // plus room for addr vects | + blob_size += head_size * maxstacks; // plus room for head thing | + blob_size += list_size * maxstacks; // plus room for our stacks | + + /* note: all of our memory is allocated in a single blob, facilitating a later free(). | + as a minimum, it is important that the result structures themselves always be | + contiguous for every stack since they are accessed through relative position. | */ + if (NULL == (p_blob = calloc(1, blob_size))) + return NULL; + + p_blob->next = info->extents; // push this extent onto... | + info->extents = p_blob; // ...some existing extents | + p_vect = (void *)p_blob + sizeof(struct stacks_extent); // prime our vector pointer | + p_blob->stacks = p_vect; // set actual vectors start | + v_head = (void *)p_vect + vect_size; // prime head pointer start | + v_list = v_head + (head_size * maxstacks); // prime our stacks pointer | + + for (i = 0; i < maxstacks; i++) { + p_head = (struct vmstat_stack *)v_head; + p_head->head = vmstat_itemize_stack((struct vmstat_result *)v_list, info->numitems, info->items); + p_blob->stacks[i] = p_head; + v_list += list_size; + v_head += head_size; + } + p_blob->ext_numstacks = maxstacks; + return p_blob; +} // end: vmstat_stacks_alloc + + +// ___ Public Functions ||||||||||||||||||||||||||||||||||||||||||||||||||||||| + +// --- standard required functions -------------------------------------------- + +/* + * procps_vmstat_new: + * + * Create a new container to hold the stat information + * + * The initial refcount is 1, and needs to be decremented + * to release the resources of the structure. + * + * Returns: < 0 on failure, 0 on success along with + * a pointer to a new context struct + */ +PROCPS_EXPORT int procps_vmstat_new ( + struct vmstat_info **info) +{ + struct vmstat_info *p; + +#ifdef ITEMTABLE_DEBUG + int i, failed = 0; + for (i = 0; i < MAXTABLE(Item_table); i++) { + if (i != Item_table[i].enumnumb) { + fprintf(stderr, "%s: enum/table error: Item_table[%d] was %s, but its value is %d\n" + , __FILE__, i, Item_table[i].enum2str, Item_table[i].enumnumb); + failed = 1; + } + } + if (failed) _Exit(EXIT_FAILURE); +#endif + + if (info == NULL || *info != NULL) + return -EINVAL; + if (!(p = calloc(1, sizeof(struct vmstat_info)))) + return -ENOMEM; + + p->refcount = 1; + p->vmstat_fd = -1; + + if (vmstat_make_hash_failed(p)) { + free(p); + return -errno; + } + + /* do a priming read here for the following potential benefits: | + 1) ensure there will be no problems with subsequent access | + 2) make delta results potentially useful, even if 1st time | + 3) elimnate need for history distortions 1st time 'switch' | */ + if (vmstat_read_failed(p)) { + procps_vmstat_unref(&p); + return -errno; + } + + *info = p; + return 0; +} // end: procps_vmstat_new + + +PROCPS_EXPORT int procps_vmstat_ref ( + struct vmstat_info *info) +{ + if (info == NULL) + return -EINVAL; + + info->refcount++; + return info->refcount; +} // end: procps_vmstat_ref + + +PROCPS_EXPORT int procps_vmstat_unref ( + struct vmstat_info **info) +{ + if (info == NULL || *info == NULL) + return -EINVAL; + + (*info)->refcount--; + + if ((*info)->refcount < 1) { + int errno_sav = errno; + + if ((*info)->vmstat_fd != -1) + close((*info)->vmstat_fd); + + if ((*info)->extents) + vmstat_extents_free_all((*info)); + if ((*info)->items) + free((*info)->items); + hdestroy_r(&(*info)->hashtab); + + free(*info); + *info = NULL; + + errno = errno_sav; + return 0; + } + return (*info)->refcount; +} // end: procps_vmstat_unref + + +// --- variable interface functions ------------------------------------------- + +PROCPS_EXPORT struct vmstat_result *procps_vmstat_get ( + struct vmstat_info *info, + enum vmstat_item item) +{ + time_t cur_secs; + + errno = EINVAL; + if (info == NULL) + return NULL; + if (item < 0 || item >= VMSTAT_logical_end) + return NULL; + errno = 0; + + /* we will NOT read the vmstat file with every call - rather, we'll offer + a granularity of 1 second between reads ... */ + cur_secs = time(NULL); + if (1 <= cur_secs - info->sav_secs) { + if (vmstat_read_failed(info)) + return NULL; + info->sav_secs = cur_secs; + } + + info->get_this.item = item; + // with 'get', we must NOT honor the usual 'noop' guarantee + info->get_this.result.ul_int = 0; + Item_table[item].setsfunc(&info->get_this, &info->hist); + + return &info->get_this; +} // end: procps_vmstat_get + + +/* procps_vmstat_select(): + * + * Harvest all the requested /proc/vmstat information then return + * it in a results stack. + * + * Returns: pointer to a vmstat_stack struct on success, NULL on error. + */ +PROCPS_EXPORT struct vmstat_stack *procps_vmstat_select ( + struct vmstat_info *info, + enum vmstat_item *items, + int numitems) +{ + errno = EINVAL; + if (info == NULL || items == NULL) + return NULL; + if (vmstat_items_check_failed(numitems, items)) + return NULL; + errno = 0; + + /* is this the first time or have things changed since we were last called? + if so, gotta' redo all of our stacks stuff ... */ + if (info->numitems != numitems + 1 + || memcmp(info->items, items, sizeof(enum vmstat_item) * numitems)) { + // allow for our VMSTAT_logical_end + if (!(info->items = realloc(info->items, sizeof(enum vmstat_item) * (numitems + 1)))) + return NULL; + memcpy(info->items, items, sizeof(enum vmstat_item) * numitems); + info->items[numitems] = VMSTAT_logical_end; + info->numitems = numitems + 1; + if (info->extents) + vmstat_extents_free_all(info); + } + if (!info->extents + && (!vmstat_stacks_alloc(info, 1))) + return NULL; + + if (vmstat_read_failed(info)) + return NULL; + vmstat_assign_results(info->extents->stacks[0], &info->hist); + + return info->extents->stacks[0]; +} // end: procps_vmstat_select + + +// --- special debugging function(s) ------------------------------------------ +/* + * The following isn't part of the normal programming interface. Rather, + * it exists to validate result types referenced in application programs. + * + * It's used only when: + * 1) the 'XTRA_PROCPS_DEBUG' has been defined, or + * 2) an #include of 'xtra-procps-debug.h' is used + */ + +PROCPS_EXPORT struct vmstat_result *xtra_vmstat_get ( + struct vmstat_info *info, + enum vmstat_item actual_enum, + const char *typestr, + const char *file, + int lineno) +{ + struct vmstat_result *r = procps_vmstat_get(info, actual_enum); + + if (actual_enum < 0 || actual_enum >= VMSTAT_logical_end) { + fprintf(stderr, "%s line %d: invalid item = %d, type = %s\n" + , file, lineno, actual_enum, typestr); + } + if (r) { + char *str = Item_table[r->item].type2str; + if (str[0] + && (strcmp(typestr, str))) + fprintf(stderr, "%s line %d: was %s, expected %s\n", file, lineno, typestr, str); + } + return r; +} // end: xtra_vmstat_get_ + + +PROCPS_EXPORT struct vmstat_result *xtra_vmstat_val ( + int relative_enum, + const char *typestr, + const struct vmstat_stack *stack, + struct vmstat_info *info, + const char *file, + int lineno) +{ + char *str; + int i; + + for (i = 0; stack->head[i].item < VMSTAT_logical_end; i++) + ; + if (relative_enum < 0 || relative_enum >= i) { + fprintf(stderr, "%s line %d: invalid relative_enum = %d, valid range = 0-%d\n" + , file, lineno, relative_enum, i-1); + return NULL; + } + str = Item_table[stack->head[relative_enum].item].type2str; + if (str[0] + && (strcmp(typestr, str))) { + fprintf(stderr, "%s line %d: was %s, expected %s\n", file, lineno, typestr, str); + } + return &stack->head[relative_enum]; + (void)info; +} // end: xtra_vmstat_val |