traffic plugin: Converted the plugin to the new plugin ifrastructure.
[collectd.git] / src / swap.c
index 1d284f3..43275fc 100644 (file)
 #if HAVE_SYS_SYSCTL_H
 #  include <sys/sysctl.h>
 #endif
+#if HAVE_KVM_H
+#  include <kvm.h>
+#endif
 
 #define MODULE_NAME "swap"
 
-#if KERNEL_LINUX || HAVE_LIBKSTAT || HAVE_SYS_SYSCTL_H || HAVE_LIBSTATGRAB
+#if KERNEL_LINUX || HAVE_LIBKSTAT || defined(VM_SWAPUSAGE) || HAVE_LIBKVM || HAVE_LIBSTATGRAB
 # define SWAP_HAVE_READ 1
 #else
 # define SWAP_HAVE_READ 0
@@ -63,13 +66,18 @@ static int ds_num = 4;
 /* #endif KERNEL_LINUX */
 
 #elif HAVE_LIBKSTAT
-static int pagesize;
+static unsigned long long pagesize;
 static kstat_t *ksp;
 /* #endif HAVE_LIBKSTAT */
 
-#elif HAVE_SYS_SYSCTL_H
+#elif defined(VM_SWAPUSAGE)
 /* No global variables */
-/* #endif HAVE_SYS_SYSCTL_H */
+/* #endif defined(VM_SWAPUSAGE) */
+
+#elif HAVE_LIBKVM
+static kvm_t *kvm_obj = NULL;
+int kvm_pagesize;
+/* #endif HAVE_LIBKVM */
 
 #elif HAVE_LIBSTATGRAB
 /* No global variables */
@@ -83,14 +91,35 @@ static void swap_init (void)
 
 #elif HAVE_LIBKSTAT
        /* getpagesize(3C) tells me this does not fail.. */
-       pagesize = getpagesize ();
+       pagesize = (unsigned long long) getpagesize ();
        if (get_kstat (&ksp, "unix", 0, "system_pages"))
                ksp = NULL;
 /* #endif HAVE_LIBKSTAT */
 
-#elif HAVE_SYS_SYSCTL_H
+#elif defined(VM_SWAPUSAGE)
        /* No init stuff */
-/* #endif HAVE_SYS_SYSCTL_H */
+/* #endif defined(VM_SWAPUSAGE) */
+
+#elif HAVE_LIBKVM
+       if (kvm_obj != NULL)
+       {
+               kvm_close (kvm_obj);
+               kvm_obj = NULL;
+       }
+
+       kvm_pagesize = getpagesize ();
+
+       if ((kvm_obj = kvm_open (NULL, /* execfile */
+                                       NULL, /* corefile */
+                                       NULL, /* swapfile */
+                                       O_RDONLY, /* flags */
+                                       NULL)) /* errstr */
+                       == NULL)
+       {
+               syslog (LOG_ERR, "swap plugin: kvm_open failed.");
+               return;
+       }
+/* #endif HAVE_LIBKVM */
 
 #elif HAVE_LIBSTATGRAB
        /* No init stuff */
@@ -175,65 +204,56 @@ static void swap_read (void)
        unsigned long long swap_alloc;
        unsigned long long swap_resv;
        unsigned long long swap_avail;
-       /* unsigned long long swap_free; */
-
-       long long availrmem;
-       long long swapfs_minfree;
 
        struct anoninfo ai;
 
        if (swapctl (SC_AINFO, &ai) == -1)
+       {
+               syslog (LOG_ERR, "swap plugin: swapctl failed: %s",
+                               strerror (errno));
                return;
+       }
 
-       availrmem      = get_kstat_value (ksp, "availrmem");
-       swapfs_minfree = get_kstat_value (ksp, "minfree");
-
-       if ((availrmem < 0LL) || (swapfs_minfree < 0LL))
-               return;
-
-       /* 
-        * Calculations learned by reading
-        * http://www.itworld.com/Comp/2377/UIR980701perf/
+       /*
+        * Calculations from:
+        * http://cvs.opensolaris.org/source/xref/on/usr/src/cmd/swap/swap.c
+        * Also see:
+        * http://www.itworld.com/Comp/2377/UIR980701perf/ (outdated?)
+        * /usr/include/vm/anon.h
+        *
+        * In short, swap -s shows: allocated + reserved = used, available
         *
-        * swap_resv += ani_resv
-        * swap_alloc += MAX(ani_resv, ani_max) - ani_free
-        * swap_avail += MAX(ani_max - ani_resv, 0) + (availrmem - swapfs_minfree)
-        * swap_free += ani_free + (availrmem - swapfs_minfree)
+        * However, Solaris does not allow to allocated/reserved more than the
+        * available swap (physical memory + disk swap), so the pedant may
+        * prefer: allocated + unallocated = reserved, available
+        * 
+        * We map the above to: used + resv = n/a, free
         *
-        * To clear up the terminology a bit:
-        * resv  = reserved (but not neccessarily used)
-        * alloc = used     (neccessarily reserved)
-        * avail = not reserved  (neccessarily free)
-        * free  = not allocates (possibly reserved)
+        * Does your brain hurt yet?  - Christophe Kalt
+        *
+        * Oh, and in case you wonder,
+        * swap_alloc = pagesize * ( ai.ani_max - ai.ani_free );
+        * can suffer from a 32bit overflow.
         */
-       swap_resv  = pagesize * ai.ani_resv;
-       swap_alloc = pagesize * (MAX(ai.ani_resv, ai.ani_max) - ai.ani_free);
-       swap_avail = pagesize * (MAX(ai.ani_max - ai.ani_resv, 0) + (availrmem - swapfs_minfree));
-       /* swap_free  = pagesize * (ai.ani_free + (availrmem - swapfs_minfree)); */
+       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 (swap_alloc, swap_avail, -1LL, swap_resv - swap_alloc);
 /* #endif HAVE_LIBKSTAT */
 
-#elif HAVE_SYS_SYSCTL_H
+#elif defined(VM_SWAPUSAGE)
        int              mib[3];
        size_t           mib_len;
        struct xsw_usage sw_usage;
        size_t           sw_usage_len;
-       int              status;
 
-#if defined(VM_SWAPUSAGE)
        mib_len = 2;
        mib[0]  = CTL_VM;
        mib[1]  = VM_SWAPUSAGE;
-#else
-       mib_len = 3;
-       if ((status = sysctlnametomib ("vm.swap_info", mib, &mib_len)) < 0)
-       {
-               syslog (LOG_WARN, "swap plugin: sysctlnametomib failed: %s",
-                               strerror (errno));
-               return;
-       }
-#endif
 
        sw_usage_len = sizeof (struct xsw_usage);
 
@@ -242,7 +262,34 @@ static void swap_read (void)
 
        /* The returned values are bytes. */
        swap_submit (sw_usage.xsu_used, sw_usage.xsu_avail, -1LL, -1LL);
-/* #endif HAVE_SYS_SYSCTL_H */
+/* #endif VM_SWAPUSAGE */
+
+#elif HAVE_LIBKVM
+       struct kvm_swap data_s;
+       int             status;
+
+       unsigned long long used;
+       unsigned long long free;
+       unsigned long long total;
+
+       if (kvm_obj == NULL)
+               return;
+
+       /* only one structure => only get the grand total, no details */
+       status = kvm_getswapinfo (kvm_obj, &data_s, 1, 0);
+       if (status == -1)
+               return;
+
+       total = (unsigned long long) data_s.ksw_total;
+       used  = (unsigned long long) data_s.ksw_used;
+
+       total *= (unsigned long long) kvm_pagesize;
+       used  *= (unsigned long long) kvm_pagesize;
+
+       free = total - used;
+
+       swap_submit (used, free, -1LL, -1LL);
+/* #endif HAVE_LIBKVM */
 
 #elif HAVE_LIBSTATGRAB
        sg_swap_stats *swap;