4a183003a0
Make the vmstat_read_failed() return non-error for Cygwin as it always will error because /proc/vmstat doesn't exist. Patch from Achim of the Cygwin project. Signed-off-by: Craig Small <csmall@dropbear.xyz>
1511 lines
65 KiB
C
1511 lines
65 KiB
C
/*
|
|
* vmstat,c - virtual memory related definitions for libprocps
|
|
*
|
|
* Copyright (C) 1995 Martin Schulze <joey@infodrom.north.de>
|
|
* Copyright (C) 1996 Charles Blake <cblake@bbn.com>
|
|
* Copyright (C) 2003 Albert Cahalan
|
|
* Copyright (C) 2015 Craig Small <csmall@dropbear.xyz>
|
|
* Copyright (C) 2016-2022 Jim Warner <james.warner@comcast.net>
|
|
*
|
|
* 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 <proc/procps-private.h>
|
|
#include <proc/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)->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
|