/**
* collectd - src/swap.c
- * Copyright (C) 2005-2007 Florian octo Forster
+ * Copyright (C) 2005-2009 Florian octo Forster
+ * Copyright (C) 2009 Stefan Völkel
*
* 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
* Florian octo Forster <octo at verplant.org>
**/
+#if HAVE_CONFIG_H
+# include "config.h"
+# undef HAVE_CONFIG_H
+#endif
+/* avoid swap.h error "Cannot use swapctl in the large files compilation environment" */
+#if HAVE_SYS_SWAP_H && !defined(_LP64) && _FILE_OFFSET_BITS == 64
+# undef _FILE_OFFSET_BITS
+# undef _LARGEFILE64_SOURCE
+#endif
+
#include "collectd.h"
#include "common.h"
#include "plugin.h"
#if HAVE_SYS_SWAP_H
# include <sys/swap.h>
#endif
+#if HAVE_VM_ANON_H
+# include <vm/anon.h>
+#endif
#if HAVE_SYS_PARAM_H
# include <sys/param.h>
#endif
#if HAVE_SYS_SYSCTL_H
# include <sys/sysctl.h>
#endif
+#if HAVE_SYS_DKSTAT_H
+# include <sys/dkstat.h>
+#endif
#if HAVE_KVM_H
# include <kvm.h>
#endif
+#if HAVE_STATGRAB_H
+# include <statgrab.h>
+#endif
+
#undef MAX
#define MAX(x,y) ((x) > (y) ? (x) : (y))
/* #endif KERNEL_LINUX */
#elif HAVE_LIBKSTAT
-static unsigned long long pagesize;
+static derive_t pagesize;
static kstat_t *ksp;
/* #endif HAVE_LIBKSTAT */
+#elif HAVE_SWAPCTL
+/* No global variables */
+/* #endif HAVE_SWAPCTL */
+
#elif defined(VM_SWAPUSAGE)
/* No global variables */
/* #endif defined(VM_SWAPUSAGE) */
-#elif HAVE_LIBKVM
+#elif HAVE_LIBKVM_GETSWAPINFO
static kvm_t *kvm_obj = NULL;
int kvm_pagesize;
-/* #endif HAVE_LIBKVM */
+/* #endif HAVE_LIBKVM_GETSWAPINFO */
#elif HAVE_LIBSTATGRAB
/* No global variables */
#elif HAVE_LIBKSTAT
/* getpagesize(3C) tells me this does not fail.. */
- pagesize = (unsigned long long) getpagesize ();
+ pagesize = (derive_t) getpagesize ();
if (get_kstat (&ksp, "unix", 0, "system_pages"))
ksp = NULL;
/* #endif HAVE_LIBKSTAT */
+#elif HAVE_SWAPCTL
+ /* No init stuff */
+/* #endif HAVE_SWAPCTL */
+
#elif defined(VM_SWAPUSAGE)
/* No init stuff */
/* #endif defined(VM_SWAPUSAGE) */
-#elif HAVE_LIBKVM
+#elif HAVE_LIBKVM_GETSWAPINFO
if (kvm_obj != NULL)
{
kvm_close (kvm_obj);
ERROR ("swap plugin: kvm_open failed.");
return (-1);
}
-/* #endif HAVE_LIBKVM */
+/* #endif HAVE_LIBKVM_GETSWAPINFO */
#elif HAVE_LIBSTATGRAB
/* No init stuff */
return (0);
}
-static void swap_submit (const char *type_instance, double value)
+static void swap_submit (const char *type_instance, derive_t value, unsigned type)
{
value_t values[1];
value_list_t vl = VALUE_LIST_INIT;
- values[0].gauge = value;
+ switch (type)
+ {
+ case DS_TYPE_GAUGE:
+ values[0].gauge = (gauge_t) value;
+ sstrncpy (vl.type, "swap", sizeof (vl.type));
+ break;
+ case DS_TYPE_DERIVE:
+ values[0].derive = value;
+ sstrncpy (vl.type, "swap_io", sizeof (vl.type));
+ break;
+ default:
+ ERROR ("swap plugin: swap_submit called with wrong"
+ " type");
+ }
vl.values = values;
vl.values_len = 1;
- vl.time = time (NULL);
- strcpy (vl.host, hostname_g);
- strcpy (vl.plugin, "swap");
- strcpy (vl.type, "swap");
+ sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+ sstrncpy (vl.plugin, "swap", sizeof (vl.plugin));
sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
plugin_dispatch_values (&vl);
#if KERNEL_LINUX
FILE *fh;
char buffer[1024];
-
+
char *fields[8];
int numfields;
- unsigned long long swap_used = 0LL;
- unsigned long long swap_cached = 0LL;
- unsigned long long swap_free = 0LL;
- unsigned long long swap_total = 0LL;
+ derive_t swap_used = 0;
+ derive_t swap_cached = 0;
+ derive_t swap_free = 0;
+ derive_t swap_total = 0;
+ derive_t swap_in = 0;
+ derive_t swap_out = 0;
if ((fh = fopen ("/proc/meminfo", "r")) == NULL)
{
while (fgets (buffer, 1024, fh) != NULL)
{
- unsigned long long *val = NULL;
+ derive_t *val = NULL;
if (strncasecmp (buffer, "SwapTotal:", 10) == 0)
val = &swap_total;
if (numfields < 2)
continue;
- *val = atoll (fields[1]) * 1024LL;
+ *val = (derive_t) atoll (fields[1]) * 1024LL;
}
if (fclose (fh))
swap_used = swap_total - (swap_free + swap_cached);
- swap_submit ("used", swap_used);
- swap_submit ("free", swap_free);
- swap_submit ("cached", swap_cached);
+ if ((fh = fopen ("/proc/vmstat", "r")) == NULL)
+ {
+ char errbuf[1024];
+ WARNING ("swap: fopen: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ return (-1);
+ }
+
+ while (fgets (buffer, 1024, fh) != NULL)
+ {
+ derive_t *val = NULL;
+
+ if (strncasecmp (buffer, "pswpin", 6) == 0)
+ val = &swap_in;
+ else if (strncasecmp (buffer, "pswpout", 7) == 0)
+ val = &swap_out;
+ else
+ continue;
+
+ numfields = strsplit (buffer, fields, 8);
+
+ if (numfields < 2)
+ continue;
+
+ *val = (derive_t) atoll (fields[1]);
+ }
+
+ if (fclose (fh))
+ {
+ char errbuf[1024];
+ WARNING ("swap: fclose: %s",
+ sstrerror (errno, errbuf, sizeof (errbuf)));
+ }
+
+ swap_submit ("used", swap_used, DS_TYPE_GAUGE);
+ swap_submit ("free", swap_free, DS_TYPE_GAUGE);
+ swap_submit ("cached", swap_cached, DS_TYPE_GAUGE);
+ swap_submit ("in", swap_in, DS_TYPE_DERIVE);
+ swap_submit ("out", swap_out, DS_TYPE_DERIVE);
+
/* #endif KERNEL_LINUX */
#elif HAVE_LIBKSTAT
- unsigned long long swap_alloc;
- unsigned long long swap_resv;
- unsigned long long swap_avail;
+ derive_t swap_alloc;
+ derive_t swap_resv;
+ derive_t swap_avail;
struct anoninfo ai;
* swap_alloc = pagesize * ( ai.ani_max - ai.ani_free );
* can suffer from a 32bit overflow.
*/
- swap_alloc = ai.ani_max - ai.ani_free;
- swap_alloc *= pagesize;
- swap_resv = ai.ani_resv + ai.ani_free - ai.ani_max;
- swap_resv *= pagesize;
- swap_avail = ai.ani_max - ai.ani_resv;
- swap_avail *= pagesize;
-
- swap_submit ("used", swap_alloc);
- swap_submit ("free", swap_avail);
- swap_submit ("reserved", swap_resv);
+ swap_alloc = (derive_t) ((ai.ani_max - ai.ani_free) * pagesize);
+ swap_resv = (derive_t) ((ai.ani_resv + ai.ani_free - ai.ani_max)
+ * pagesize);
+ swap_avail = (derive_t) ((ai.ani_max - ai.ani_resv) * pagesize);
+
+ swap_submit ("used", swap_alloc, DS_TYPE_GAUGE);
+ swap_submit ("free", swap_avail, DS_TYPE_GAUGE);
+ swap_submit ("reserved", swap_resv, DS_TYPE_GAUGE);
/* #endif HAVE_LIBKSTAT */
+#elif HAVE_SWAPCTL
+ struct swapent *swap_entries;
+ int swap_num;
+ int status;
+ int i;
+
+ derive_t used = 0;
+ derive_t total = 0;
+
+ /*
+ * XXX: This is the syntax for the *BSD `swapctl', which has the
+ * following prototype:
+ * swapctl (int cmd, void *arg, int misc);
+ *
+ * HP-UX and Solaris (and possibly other UNIXes) provide `swapctl',
+ * too, but with the following prototype:
+ * swapctl (int cmd, void *arg);
+ *
+ * Solaris is usually handled in the KSTAT case above. For other UNIXes
+ * a separate case for the other version of `swapctl' may be necessary.
+ */
+ swap_num = swapctl (SWAP_NSWAP, NULL, 0);
+ if (swap_num < 0)
+ {
+ ERROR ("swap plugin: swapctl (SWAP_NSWAP) failed with status %i.",
+ swap_num);
+ return (-1);
+ }
+ else if (swap_num == 0)
+ return (0);
+
+ swap_entries = calloc (swap_num, sizeof (*swap_entries));
+ if (swap_entries == NULL)
+ {
+ ERROR ("swap plugin: calloc failed.");
+ return (-1);
+ }
+
+ status = swapctl (SWAP_STATS, swap_entries, swap_num);
+ if (status != swap_num)
+ {
+ ERROR ("swap plugin: swapctl (SWAP_STATS) failed with status %i.",
+ status);
+ sfree (swap_entries);
+ return (-1);
+ }
+
+#if defined(DEV_BSIZE) && (DEV_BSIZE > 0)
+# define C_SWAP_BLOCK_SIZE ((derive_t) DEV_BSIZE)
+#else
+# define C_SWAP_BLOCK_SIZE ((derive_t) 512)
+#endif
+
+ for (i = 0; i < swap_num; i++)
+ {
+ if ((swap_entries[i].se_flags & SWF_ENABLE) == 0)
+ continue;
+
+ used += ((derive_t) swap_entries[i].se_inuse)
+ * C_SWAP_BLOCK_SIZE;
+ total += ((derive_t) swap_entries[i].se_nblks)
+ * C_SWAP_BLOCK_SIZE;
+ }
+
+ if (total < used)
+ {
+ ERROR ("swap plugin: Total swap space (%"PRIu64") "
+ "is less than used swap space (%"PRIu64").",
+ total, used);
+ return (-1);
+ }
+
+ swap_submit ("used", used, DS_TYPE_GAUGE);
+ swap_submit ("free", total - used, DS_TYPE_GAUGE);
+
+ sfree (swap_entries);
+/* #endif HAVE_SWAPCTL */
+
#elif defined(VM_SWAPUSAGE)
int mib[3];
size_t mib_len;
return (-1);
/* The returned values are bytes. */
- swap_submit ("used", sw_usage.xsu_used);
- swap_submit ("free", sw_usage.xsu_avail);
+ swap_submit ("used", (derive_t) sw_usage.xsu_used, DS_TYPE_GAUGE);
+ swap_submit ("free", (derive_t) sw_usage.xsu_avail, DS_TYPE_GAUGE);
/* #endif VM_SWAPUSAGE */
-#elif HAVE_LIBKVM
+#elif HAVE_LIBKVM_GETSWAPINFO
struct kvm_swap data_s;
int status;
- unsigned long long used;
- unsigned long long free;
- unsigned long long total;
+ derive_t used;
+ derive_t free;
+ derive_t total;
if (kvm_obj == NULL)
return (-1);
if (status == -1)
return (-1);
- total = (unsigned long long) data_s.ksw_total;
- used = (unsigned long long) data_s.ksw_used;
+ total = (derive_t) data_s.ksw_total;
+ used = (derive_t) data_s.ksw_used;
- total *= (unsigned long long) kvm_pagesize;
- used *= (unsigned long long) kvm_pagesize;
+ total *= (derive_t) kvm_pagesize;
+ used *= (derive_t) kvm_pagesize;
free = total - used;
- swap_submit ("used", used);
- swap_submit ("free", free);
-/* #endif HAVE_LIBKVM */
+ swap_submit ("used", used, DS_TYPE_GAUGE);
+ swap_submit ("free", free, DS_TYPE_GAUGE);
+/* #endif HAVE_LIBKVM_GETSWAPINFO */
#elif HAVE_LIBSTATGRAB
sg_swap_stats *swap;
if (swap == NULL)
return (-1);
- swap_submit ("used", swap->used);
- swap_submit ("free", swap->free);
+ swap_submit ("used", (derive_t) swap->used, DS_TYPE_GAUGE);
+ swap_submit ("free", (derive_t) swap->free, DS_TYPE_GAUGE);
#endif /* HAVE_LIBSTATGRAB */
return (0);