Code

vmem plugin: Added a plugin to collect virtual memory statistics.
authorFlorian Forster <octo@noris.net>
Thu, 27 Mar 2008 14:42:40 +0000 (15:42 +0100)
committerFlorian Forster <octo@noris.net>
Thu, 27 Mar 2008 14:42:40 +0000 (15:42 +0100)
README
configure.in
src/Makefile.am
src/collectd.conf.in
src/types.db
src/vmem.c [new file with mode: 0644]

diff --git a/README b/README
index 9dba7cde7e5cf52da88e96aafdd08ac9462b9a29..f298bd3aa8142d0dc91c0e486f52d47d6ea32827 100644 (file)
--- 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 <http://linux-vserver.org/>.
index d53706dfbb87807975e57b234548c3eb291e8299..8175746dcb2596f2288e68f50d531b44fac98207 100644 (file)
@@ -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
index 618ef0a208f86acaebde423b7f7813e2549c6498..594c4bbcbd17fdfca5e391c3ec9e9b1accb9b154 100644 (file)
@@ -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
index e125bb63173ee7585e71902feee3dacfa79cc071..c5102cd51fc182eb8cb948ffbbf5633fee966b86 100644 (file)
@@ -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
index a19f26dc997a9d2513f8dc3d5221307384ebfa9f..6449aacefafbd78ec2bdd834594304f196c1ae1b 100644 (file)
@@ -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 (file)
index 0000000..3235cb6
--- /dev/null
@@ -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 <octo at verplant.org>
+ **/
+
+#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 : */