From 7b6abfd016cda55f7c4e858db09da16444fc1fb5 Mon Sep 17 00:00:00 2001 From: Florian Forster Date: Thu, 27 Mar 2008 15:42:40 +0100 Subject: [PATCH] vmem plugin: Added a plugin to collect virtual memory statistics. --- README | 4 + configure.in | 4 + src/Makefile.am | 8 ++ src/collectd.conf.in | 1 + src/types.db | 4 + src/vmem.c | 251 +++++++++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 272 insertions(+) create mode 100644 src/vmem.c diff --git a/README b/README index 9dba7cde..f298bd3a 100644 --- a/README +++ b/README @@ -169,6 +169,10 @@ Features - users Users currently logged in. + - vmem + Virtual memory statistics, e. g. the number of page-ins/-outs or the + number of pagefaults. + - vserver System resources used by Linux VServers. See . diff --git a/configure.in b/configure.in index d53706df..8175746d 100644 --- a/configure.in +++ b/configure.in @@ -2050,6 +2050,7 @@ plugin_swap="no" plugin_tape="no" plugin_tcpconns="no" plugin_users="no" +plugin_vmem="no" plugin_vserver="no" plugin_wireless="no" @@ -2070,6 +2071,7 @@ then plugin_serial="yes" plugin_swap="yes" plugin_tcpconns="yes" + plugin_vmem="yes" plugin_vserver="yes" plugin_wireless="yes" @@ -2228,6 +2230,7 @@ AC_PLUGIN([tcpconns], [$plugin_tcpconns], [TCP connection statistics]) AC_PLUGIN([unixsock], [yes], [Unixsock communication plugin]) AC_PLUGIN([users], [$plugin_users], [User statistics]) AC_PLUGIN([uuid], [yes], [UUID as hostname plugin]) +AC_PLUGIN([vmem], [$plugin_vmem], [Virtual memory statistics]) AC_PLUGIN([vserver], [$plugin_vserver], [Linux VServer statistics]) AC_PLUGIN([wireless], [$plugin_wireless], [Wireless statistics]) AC_PLUGIN([xmms], [$with_libxmms], [XMMS statistics]) @@ -2367,6 +2370,7 @@ Configuration: unixsock . . . . . $enable_unixsock users . . . . . . . $enable_users uuid . . . . . . . $enable_uuid + vmem . . . . . . . $enable_vmem vserver . . . . . . $enable_vserver wireless . . . . . $enable_wireless xmms . . . . . . . $enable_xmms diff --git a/src/Makefile.am b/src/Makefile.am index 618ef0a2..594c4bbc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -623,6 +623,14 @@ collectd_LDADD += "-dlopen" uuid.la collectd_DEPENDENCIES += uuid.la endif +if BUILD_PLUGIN_VMEM +pkglib_LTLIBRARIES += vmem.la +vmem_la_SOURCES = vmem.c +vmem_la_LDFLAGS = -module -avoid-version +collectd_LDADD += "-dlopen" vmem.la +collectd_DEPENDENCIES += vmem.la +endif + if BUILD_PLUGIN_VSERVER pkglib_LTLIBRARIES += vserver.la vserver_la_SOURCES = vserver.c diff --git a/src/collectd.conf.in b/src/collectd.conf.in index e125bb63..c5102cd5 100644 --- a/src/collectd.conf.in +++ b/src/collectd.conf.in @@ -59,6 +59,7 @@ FQDNLookup true @BUILD_PLUGIN_UNIXSOCK_TRUE@LoadPlugin unixsock @BUILD_PLUGIN_USERS_TRUE@LoadPlugin users @BUILD_PLUGIN_UUID_TRUE@LoadPlugin uuid +@BUILD_PLUGIN_VMEM_TRUE@LoadPlugin vmem @BUILD_PLUGIN_VSERVER_TRUE@LoadPlugin vserver @BUILD_PLUGIN_WIRELESS_TRUE@LoadPlugin wireless @BUILD_PLUGIN_XMMS_TRUE@LoadPlugin xmms diff --git a/src/types.db b/src/types.db index a19f26dc..6449aace 100644 --- a/src/types.db +++ b/src/types.db @@ -77,6 +77,10 @@ time_offset seconds:GAUGE:-1000000:1000000 users users:GAUGE:0:65535 virt_cpu_total ns:COUNTER:0:256000000000 virt_vcpu ns:COUNTER:0:1000000000 +vmpage_action value:COUNTER:0:4294967295 +vmpage_number value:GAUGE:0:4294967295 +vmpage_faults minflt:COUNTER:0:9223372036854775807, majflt:COUNTER:0:9223372036854775807 +vmpage_io in:COUNTER:0:4294967295, out:COUNTER:0:4294967295 voltage_threshold value:GAUGE:U:U, threshold:GAUGE:U:U voltage value:GAUGE:U:U vs_memory value:GAUGE:0:9223372036854775807 diff --git a/src/vmem.c b/src/vmem.c new file mode 100644 index 00000000..3235cb68 --- /dev/null +++ b/src/vmem.c @@ -0,0 +1,251 @@ +/** + * collectd - src/vmem.c + * Copyright (C) 2008 Florian octo Forster + * + * 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; only version 2 of the License is applicable. + * + * 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. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + * Authors: + * Florian octo Forster + **/ + +#include "collectd.h" +#include "common.h" +#include "plugin.h" + +#if KERNEL_LINUX +/* No global variables */ +/* #endif KERNEL_LINUX */ + +#else +# error "No applicable input method." +#endif /* HAVE_LIBSTATGRAB */ + +static void submit (const char *plugin_instance, const char *type, + const char *type_instance, value_t *values, int values_len) +{ + value_list_t vl = VALUE_LIST_INIT; + + vl.values = values; + vl.values_len = values_len; + + vl.time = time (NULL); + strcpy (vl.host, hostname_g); + strcpy (vl.plugin, "vmem"); + if (plugin_instance != NULL) + sstrncpy (vl.plugin_instance, plugin_instance, sizeof (vl.plugin_instance)); + if (type_instance != NULL) + sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance)); + + plugin_dispatch_values (type, &vl); +} /* void vmem_submit */ + +static void submit_two (const char *plugin_instance, const char *type, + const char *type_instance, counter_t c0, counter_t c1) +{ + value_t values[2]; + + values[0].counter = c0; + values[1].counter = c1; + + submit (plugin_instance, type, type_instance, values, 2); +} /* void submit_one */ + +static void submit_one (const char *plugin_instance, const char *type, + const char *type_instance, value_t value) +{ + submit (plugin_instance, type, type_instance, &value, 1); +} /* void submit_one */ + +static int vmem_read (void) +{ +#if KERNEL_LINUX + counter_t pgpgin = 0; + counter_t pgpgout = 0; + int pgpgvalid = 0; + + counter_t pswpin = 0; + counter_t pswpout = 0; + int pswpvalid = 0; + + counter_t pgfault = 0; + counter_t pgmajfault = 0; + int pgfaultvalid = 0; + + FILE *fh; + char buffer[1024]; + + fh = fopen ("/proc/vmstat", "r"); + if (fh == NULL) + { + char errbuf[1024]; + ERROR ("vmem plugin: fopen (/proc/vmstat) failed: %s", + sstrerror (errno, errbuf, sizeof (errbuf))); + return (-1); + } + + while (fgets (buffer, sizeof (buffer), fh) != NULL) + { + char *fields[4]; + int fields_num; + char *key; + char *endptr; + counter_t counter; + gauge_t gauge; + + fields_num = strsplit (buffer, fields, STATIC_ARRAY_SIZE (fields)); + if (fields_num != 2) + continue; + + key = fields[0]; + + endptr = NULL; + counter = strtoll (fields[1], &endptr, 10); + if (fields[1] == endptr) + continue; + + endptr = NULL; + gauge = strtod (fields[1], &endptr); + if (fields[1] == endptr) + continue; + + /* + * Number of pages + * + * The total number of {inst} pages, e. g dirty pages. + */ + if (strncmp ("nr_", key, strlen ("nr_")) == 0) + { + char *inst = key + strlen ("nr_"); + value_t value = { .gauge = gauge }; + submit_one (NULL, "vmpage_number", inst, value); + } + + /* + * Number of page allocations, refills, steals and scans. This is collected + * ``per zone'', i. e. for DMA, DMA32, normal and possibly highmem. + */ + else if (strncmp ("pgalloc_", key, strlen ("pgalloc_")) == 0) + { + char *inst = key + strlen ("pgalloc_"); + value_t value = { .counter = counter }; + submit_one (inst, "vmpage_action", "alloc", value); + } + else if (strncmp ("pgrefill_", key, strlen ("pgrefill_")) == 0) + { + char *inst = key + strlen ("pgrefill_"); + value_t value = { .counter = counter }; + submit_one (inst, "vmpage_action", "refill", value); + } + else if (strncmp ("pgsteal_", key, strlen ("pgsteal_")) == 0) + { + char *inst = key + strlen ("pgsteal_"); + value_t value = { .counter = counter }; + submit_one (inst, "vmpage_action", "steal", value); + } + else if (strncmp ("pgscan_kswapd_", key, strlen ("pgscan_kswapd_")) == 0) + { + char *inst = key + strlen ("pgscan_kswapd_"); + value_t value = { .counter = counter }; + submit_one (inst, "vmpage_action", "scan_kswapd", value); + } + else if (strncmp ("pgscan_direct_", key, strlen ("pgscan_direct_")) == 0) + { + char *inst = key + strlen ("pgscan_direct_"); + value_t value = { .counter = counter }; + submit_one (inst, "vmpage_action", "scan_direct", value); + } + + /* + * Page in and page outs. For memory and swap. + */ + else if (strcmp ("pgpgin", key) == 0) + { + pgpgin = counter; + pgpgvalid |= 0x01; + } + else if (strcmp ("pgpgout", key) == 0) + { + pgpgout = counter; + pgpgvalid |= 0x02; + } + else if (strcmp ("pswpin", key) == 0) + { + pswpin = counter; + pswpvalid |= 0x01; + } + else if (strcmp ("pswpout", key) == 0) + { + pswpout = counter; + pswpvalid |= 0x02; + } + + /* + * Pagefaults + */ + else if (strcmp ("pgfault", key) == 0) + { + pgfault = counter; + pgfaultvalid |= 0x01; + } + else if (strcmp ("pgmajfault", key) == 0) + { + pgmajfault = counter; + pgfaultvalid |= 0x02; + } + + /* + * Page action + * + * number of pages moved to the active or inactive lists and freed, i. e. + * removed from either list. + */ + else if (strcmp ("pgfree", key) == 0) + { + value_t value = { .counter = counter }; + submit_one (NULL, "vmpage_action", "free", value); + } + else if (strcmp ("pgactivate", key) == 0) + { + value_t value = { .counter = counter }; + submit_one (NULL, "vmpage_action", "activate", value); + } + else if (strcmp ("pgdeactivate", key) == 0) + { + value_t value = { .counter = counter }; + submit_one (NULL, "vmpage_action", "deactivate", value); + } + } /* while (fgets) */ + + fclose (fh); + fh = NULL; + + if (pgfaultvalid == 0x03) + submit_two (NULL, "vmpage_faults", NULL, pgfault, pgmajfault); + + if (pgpgvalid == 0x03) + submit_two (NULL, "vmpage_io", "memory", pgpgin, pgpgout); + + if (pswpvalid == 0x03) + submit_two (NULL, "vmpage_io", "swap", pswpin, pswpout); +#endif /* KERNEL_LINUX */ + + return (0); +} /* int vmem_read */ + +void module_register (void) +{ + plugin_register_read ("vmem", vmem_read); +} /* void module_register */ + +/* vim: set sw=2 sts=2 ts=8 : */ -- 2.11.0