diff options
author | Igor Pashev <pashev.igor@gmail.com> | 2014-10-26 12:33:50 +0400 |
---|---|---|
committer | Igor Pashev <pashev.igor@gmail.com> | 2014-10-26 12:33:50 +0400 |
commit | 47e6e7c84f008a53061e661f31ae96629bc694ef (patch) | |
tree | 648a07f3b5b9d67ce19b0fd72e8caa1175c98f1a /src/pmdas/linux/proc_vmstat.c | |
download | pcp-debian/3.9.10.tar.gz |
Debian 3.9.10debian/3.9.10debian
Diffstat (limited to 'src/pmdas/linux/proc_vmstat.c')
-rw-r--r-- | src/pmdas/linux/proc_vmstat.c | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/src/pmdas/linux/proc_vmstat.c b/src/pmdas/linux/proc_vmstat.c new file mode 100644 index 0000000..f56c3c3 --- /dev/null +++ b/src/pmdas/linux/proc_vmstat.c @@ -0,0 +1,299 @@ +/* + * Linux /proc/vmstat metrics cluster + * + * Copyright (c) 2013-2014 Red Hat. + * Copyright (c) 2007,2011 Aconex. All Rights Reserved. + * Copyright (c) 2004 Silicon Graphics, Inc. All Rights Reserved. + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program 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 General Public License + * for more details. + */ + +#include <ctype.h> +#include "pmapi.h" +#include "pmda.h" +#include "indom.h" +#include "proc_vmstat.h" + +static struct { + const char *field; + __uint64_t *offset; +} vmstat_fields[] = { + /* sorted by name to make maintenance easier */ + { .field = "allocstall", + .offset = &_pm_proc_vmstat.allocstall }, + { .field = "compact_blocks_moved", + .offset = &_pm_proc_vmstat.compact_blocks_moved }, + { .field = "compact_fail", + .offset = &_pm_proc_vmstat.compact_fail }, + { .field = "compact_pagemigrate_failed", + .offset = &_pm_proc_vmstat.compact_pagemigrate_failed }, + { .field = "compact_pages_moved", + .offset = &_pm_proc_vmstat.compact_pages_moved }, + { .field = "compact_stall", + .offset = &_pm_proc_vmstat.compact_stall }, + { .field = "compact_success", + .offset = &_pm_proc_vmstat.compact_success }, + { .field = "htlb_buddy_alloc_fail", + .offset = &_pm_proc_vmstat.htlb_buddy_alloc_fail }, + { .field = "htlb_buddy_alloc_success", + .offset = &_pm_proc_vmstat.htlb_buddy_alloc_success }, + { .field = "kswapd_inodesteal", + .offset = &_pm_proc_vmstat.kswapd_inodesteal }, + { .field = "kswapd_low_wmark_hit_quickly", + .offset = &_pm_proc_vmstat.kswapd_low_wmark_hit_quickly }, + { .field = "kswapd_high_wmark_hit_quickly", + .offset = &_pm_proc_vmstat.kswapd_high_wmark_hit_quickly }, + { .field = "kswapd_skip_congestion_wait", + .offset = &_pm_proc_vmstat.kswapd_skip_congestion_wait }, + { .field = "kswapd_steal", + .offset = &_pm_proc_vmstat.kswapd_steal }, + { .field = "nr_active_anon", + .offset = &_pm_proc_vmstat.nr_active_anon }, + { .field = "nr_active_file", + .offset = &_pm_proc_vmstat.nr_active_file }, + { .field = "nr_anon_pages", + .offset = &_pm_proc_vmstat.nr_anon_pages }, + { .field = "nr_anon_transparent_hugepages", + .offset = &_pm_proc_vmstat.nr_anon_transparent_hugepages }, + { .field = "nr_bounce", + .offset = &_pm_proc_vmstat.nr_bounce }, + { .field = "nr_dirty", + .offset = &_pm_proc_vmstat.nr_dirty }, + { .field = "nr_dirtied", + .offset = &_pm_proc_vmstat.nr_dirtied }, + { .field = "nr_dirty_threshold", + .offset = &_pm_proc_vmstat.nr_dirty_threshold }, + { .field = "nr_dirty_background_threshold", + .offset = &_pm_proc_vmstat.nr_dirty_background_threshold }, + { .field = "nr_file_pages", + .offset = &_pm_proc_vmstat.nr_file_pages }, + { .field = "nr_free_pages", + .offset = &_pm_proc_vmstat.nr_free_pages }, + { .field = "nr_inactive_anon", + .offset = &_pm_proc_vmstat.nr_inactive_anon }, + { .field = "nr_inactive_file", + .offset = &_pm_proc_vmstat.nr_inactive_file }, + { .field = "nr_isolated_anon", + .offset = &_pm_proc_vmstat.nr_isolated_anon }, + { .field = "nr_isolated_file", + .offset = &_pm_proc_vmstat.nr_isolated_file }, + { .field = "nr_kernel_stack", + .offset = &_pm_proc_vmstat.nr_kernel_stack }, + { .field = "nr_mapped", + .offset = &_pm_proc_vmstat.nr_mapped }, + { .field = "nr_mlock", + .offset = &_pm_proc_vmstat.nr_mlock }, + { .field = "nr_page_table_pages", + .offset = &_pm_proc_vmstat.nr_page_table_pages }, + { .field = "nr_shmem", + .offset = &_pm_proc_vmstat.nr_shmem }, + { .field = "nr_slab_reclaimable", + .offset = &_pm_proc_vmstat.nr_slab_reclaimable }, + { .field = "nr_slab_unreclaimable", + .offset = &_pm_proc_vmstat.nr_slab_unreclaimable }, + { .field = "nr_slab", + .offset = &_pm_proc_vmstat.nr_slab }, /* not in later kernels */ + { .field = "nr_unevictable", + .offset = &_pm_proc_vmstat.nr_unevictable }, + { .field = "nr_unstable", + .offset = &_pm_proc_vmstat.nr_unstable }, + { .field = "nr_vmscan_write", + .offset = &_pm_proc_vmstat.nr_vmscan_write }, + { .field = "nr_writeback", + .offset = &_pm_proc_vmstat.nr_writeback }, + { .field = "nr_writeback_temp", + .offset = &_pm_proc_vmstat.nr_writeback_temp }, + { .field = "nr_written", + .offset = &_pm_proc_vmstat.nr_written }, + { .field = "numa_hit", + .offset = &_pm_proc_vmstat.numa_hit }, + { .field = "numa_miss", + .offset = &_pm_proc_vmstat.numa_miss }, + { .field = "numa_foreign", + .offset = &_pm_proc_vmstat.numa_foreign }, + { .field = "numa_interleave", + .offset = &_pm_proc_vmstat.numa_interleave }, + { .field = "numa_local", + .offset = &_pm_proc_vmstat.numa_local }, + { .field = "numa_other", + .offset = &_pm_proc_vmstat.numa_other }, + { .field = "pageoutrun", + .offset = &_pm_proc_vmstat.pageoutrun }, + { .field = "pgactivate", + .offset = &_pm_proc_vmstat.pgactivate }, + { .field = "pgalloc_dma", + .offset = &_pm_proc_vmstat.pgalloc_dma }, + { .field = "pgalloc_dma32", + .offset = &_pm_proc_vmstat.pgalloc_dma32 }, + { .field = "pgalloc_high", + .offset = &_pm_proc_vmstat.pgalloc_high }, + { .field = "pgalloc_movable", + .offset = &_pm_proc_vmstat.pgalloc_movable }, + { .field = "pgalloc_normal", + .offset = &_pm_proc_vmstat.pgalloc_normal }, + { .field = "pgdeactivate", + .offset = &_pm_proc_vmstat.pgdeactivate }, + { .field = "pgfault", + .offset = &_pm_proc_vmstat.pgfault }, + { .field = "pgfree", + .offset = &_pm_proc_vmstat.pgfree }, + { .field = "pginodesteal", + .offset = &_pm_proc_vmstat.pginodesteal }, + { .field = "pgmajfault", + .offset = &_pm_proc_vmstat.pgmajfault }, + { .field = "pgpgin", + .offset = &_pm_proc_vmstat.pgpgin }, + { .field = "pgpgout", + .offset = &_pm_proc_vmstat.pgpgout }, + { .field = "pgrefill_dma", + .offset = &_pm_proc_vmstat.pgrefill_dma }, + { .field = "pgrefill_dma32", + .offset = &_pm_proc_vmstat.pgrefill_dma32 }, + { .field = "pgrefill_high", + .offset = &_pm_proc_vmstat.pgrefill_high }, + { .field = "pgrefill_movable", + .offset = &_pm_proc_vmstat.pgrefill_movable }, + { .field = "pgrefill_normal", + .offset = &_pm_proc_vmstat.pgrefill_normal }, + { .field = "pgrotated", + .offset = &_pm_proc_vmstat.pgrotated }, + { .field = "pgscan_direct_dma", + .offset = &_pm_proc_vmstat.pgscan_direct_dma }, + { .field = "pgscan_direct_dma32", + .offset = &_pm_proc_vmstat.pgscan_direct_dma32 }, + { .field = "pgscan_direct_high", + .offset = &_pm_proc_vmstat.pgscan_direct_high }, + { .field = "pgscan_direct_movable", + .offset = &_pm_proc_vmstat.pgscan_direct_movable }, + { .field = "pgscan_direct_normal", + .offset = &_pm_proc_vmstat.pgscan_direct_normal }, + { .field = "pgscan_kswapd_dma", + .offset = &_pm_proc_vmstat.pgscan_kswapd_dma }, + { .field = "pgscan_kswapd_dma32", + .offset = &_pm_proc_vmstat.pgscan_kswapd_dma32 }, + { .field = "pgscan_kswapd_high", + .offset = &_pm_proc_vmstat.pgscan_kswapd_high }, + { .field = "pgscan_kswapd_movable", + .offset = &_pm_proc_vmstat.pgscan_kswapd_movable }, + { .field = "pgscan_kswapd_normal", + .offset = &_pm_proc_vmstat.pgscan_kswapd_normal }, + { .field = "pgsteal_dma", + .offset = &_pm_proc_vmstat.pgsteal_dma }, + { .field = "pgsteal_dma32", + .offset = &_pm_proc_vmstat.pgsteal_dma32 }, + { .field = "pgsteal_high", + .offset = &_pm_proc_vmstat.pgsteal_high }, + { .field = "pgsteal_movable", + .offset = &_pm_proc_vmstat.pgsteal_movable }, + { .field = "pgsteal_normal", + .offset = &_pm_proc_vmstat.pgsteal_normal }, + { .field = "pswpin", + .offset = &_pm_proc_vmstat.pswpin }, + { .field = "pswpout", + .offset = &_pm_proc_vmstat.pswpout }, + { .field = "slabs_scanned", + .offset = &_pm_proc_vmstat.slabs_scanned }, + { .field = "thp_collapse_alloc", + .offset = &_pm_proc_vmstat.thp_collapse_alloc }, + { .field = "thp_collapse_alloc_failed", + .offset = &_pm_proc_vmstat.thp_collapse_alloc_failed }, + { .field = "thp_fault_alloc", + .offset = &_pm_proc_vmstat.thp_fault_alloc }, + { .field = "thp_fault_fallback", + .offset = &_pm_proc_vmstat.thp_fault_fallback }, + { .field = "thp_split", + .offset = &_pm_proc_vmstat.thp_split }, + { .field = "unevictable_pgs_cleared", + .offset = &_pm_proc_vmstat.unevictable_pgs_cleared }, + { .field = "unevictable_pgs_culled", + .offset = &_pm_proc_vmstat.unevictable_pgs_culled }, + { .field = "unevictable_pgs_mlocked", + .offset = &_pm_proc_vmstat.unevictable_pgs_mlocked }, + { .field = "unevictable_pgs_mlockfreed", + .offset = &_pm_proc_vmstat.unevictable_pgs_mlockfreed }, + { .field = "unevictable_pgs_munlocked", + .offset = &_pm_proc_vmstat.unevictable_pgs_munlocked }, + { .field = "unevictable_pgs_rescued", + .offset = &_pm_proc_vmstat.unevictable_pgs_rescued }, + { .field = "unevictable_pgs_scanned", + .offset = &_pm_proc_vmstat.unevictable_pgs_scanned }, + { .field = "unevictable_pgs_stranded", + .offset = &_pm_proc_vmstat.unevictable_pgs_stranded }, + { .field = "zone_reclaim_failed", + .offset = &_pm_proc_vmstat.zone_reclaim_failed }, + + { .field = NULL, .offset = NULL } +}; + +#define VMSTAT_OFFSET(ii, pp) (int64_t *)((char *)pp + \ + (__psint_t)vmstat_fields[ii].offset - (__psint_t)&_pm_proc_vmstat) + +void +proc_vmstat_init(void) +{ + char buf[1024]; + + /* + * The swap metrics moved from /proc/stat to /proc/vmstat early in 2.6. + * In addition, the swap operation count was removed; the fetch routine + * needs to deal with these quirks and return something sensible based + * (initially) on whether the vmstat file exists. + * + * We'll re-evaluate this on each fetch of the mem.vmstat metrics, but + * that is not a problem. This routine makes sure any swap.xxx metric + * fetch without a preceding mem.vmstat fetch has the correct state. + */ + snprintf(buf, sizeof(buf), "%s/proc/vmstat", linux_statspath); + _pm_have_proc_vmstat = (access(buf, R_OK) == 0); +} + +int +refresh_proc_vmstat(proc_vmstat_t *proc_vmstat) +{ + char buf[1024]; + char *bufp; + int64_t *p; + int i; + FILE *fp; + + for (i = 0; vmstat_fields[i].field != NULL; i++) { + p = VMSTAT_OFFSET(i, proc_vmstat); + *p = -1; /* marked as "no value available" */ + } + + if ((fp = linux_statsfile("/proc/vmstat", buf, sizeof(buf))) == NULL) + return -oserror(); + + _pm_have_proc_vmstat = 1; + + while (fgets(buf, sizeof(buf), fp) != NULL) { + if ((bufp = strchr(buf, ' ')) == NULL) + continue; + *bufp = '\0'; + for (i = 0; vmstat_fields[i].field != NULL; i++) { + if (strcmp(buf, vmstat_fields[i].field) != 0) + continue; + p = VMSTAT_OFFSET(i, proc_vmstat); + for (bufp++; *bufp; bufp++) { + if (isdigit((int)*bufp)) { + sscanf(bufp, "%llu", (unsigned long long *)p); + break; + } + } + } + } + fclose(fp); + + if (proc_vmstat->nr_slab == -1) /* split apart in 2.6.18 */ + proc_vmstat->nr_slab = proc_vmstat->nr_slab_reclaimable + + proc_vmstat->nr_slab_unreclaimable; + return 0; +} |