]> arthur.barton.de Git - netdata.git/commitdiff
Add some basic system stats - load, cpu, interrupts, processes
authorVladimir Kobal <vlad@prokk.net>
Sat, 3 Dec 2016 21:17:18 +0000 (23:17 +0200)
committerVladimir Kobal <vlad@prokk.net>
Sat, 3 Dec 2016 21:17:18 +0000 (23:17 +0200)
src/Makefile.am
src/freebsd_loadavg.c [new file with mode: 0644]
src/freebsd_stat.c [new file with mode: 0644]
src/main.c
src/plugin_freebsd.c
src/plugin_freebsd.h

index 0472f997f926498b590f1ef4f4098821df240084..baecba22990c012756289471df857f6f4171a863 100644 (file)
@@ -62,6 +62,8 @@ netdata_SOURCES = \
 if FREEBSD
 netdata_SOURCES += \
        plugin_freebsd.c plugin_freebsd.h \
+       freebsd_loadavg.c \
+       freebsd_stat.c \
        $(NULL)
 else
 netdata_SOURCES += \
diff --git a/src/freebsd_loadavg.c b/src/freebsd_loadavg.c
new file mode 100644 (file)
index 0000000..d4e3594
--- /dev/null
@@ -0,0 +1,78 @@
+#include "common.h"
+#include <sys/vmmeter.h>
+
+// FreeBSD calculates this once every 5 seconds
+#define MIN_LOADAVG_UPDATE_EVERY 5
+
+int do_proc_loadavg(int update_every, unsigned long long dt) {
+    (void)dt;
+
+    static int do_loadavg = -1, do_all_processes = -1;
+    static unsigned long long last_loadavg_usec = 0;
+    static RRDSET *load_chart = NULL, *processes_chart = NULL;
+
+    if(unlikely(do_loadavg == -1)) {
+        do_loadavg          = config_get_boolean("plugin:proc:/proc/loadavg", "enable load average", 1);
+        do_all_processes    = config_get_boolean("plugin:proc:/proc/loadavg", "enable total processes", 1);
+    }
+
+    struct loadavg sysload;
+    
+    if (unlikely(GETSYSCTL("vm.loadavg", sysload)))
+        return 1;
+    
+    double load1 = (double)sysload.ldavg[0] / sysload.fscale;
+    double load5 = (double)sysload.ldavg[1] / sysload.fscale;
+    double load15 = (double)sysload.ldavg[2] / sysload.fscale;
+
+    struct vmtotal total;
+    
+    if (unlikely(GETSYSCTL("vm.vmtotal", total)))
+        return 1;
+    
+    unsigned long long active_processes     = total.t_rq + total.t_dw + total.t_pw + total.t_sl + total.t_sw;
+
+    // --------------------------------------------------------------------
+
+    if(last_loadavg_usec <= dt) {
+        if(likely(do_loadavg)) {
+            if(unlikely(!load_chart)) {
+                load_chart = rrdset_find_byname("system.load");
+                if(unlikely(!load_chart)) {
+                    load_chart = rrdset_create("system", "load", NULL, "load", NULL, "System Load Average", "load", 100, (update_every < MIN_LOADAVG_UPDATE_EVERY) ? MIN_LOADAVG_UPDATE_EVERY : update_every, RRDSET_TYPE_LINE);
+                    rrddim_add(load_chart, "load1", NULL, 1, 1000, RRDDIM_ABSOLUTE);
+                    rrddim_add(load_chart, "load5", NULL, 1, 1000, RRDDIM_ABSOLUTE);
+                    rrddim_add(load_chart, "load15", NULL, 1, 1000, RRDDIM_ABSOLUTE);
+                }
+            }
+            else
+                rrdset_next(load_chart);
+
+            rrddim_set(load_chart, "load1", (collected_number) (load1 * 1000));
+            rrddim_set(load_chart, "load5", (collected_number) (load5 * 1000));
+            rrddim_set(load_chart, "load15", (collected_number) (load15 * 1000));
+            rrdset_done(load_chart);
+        }
+
+        last_loadavg_usec = load_chart->update_every * 1000000ULL;
+    }
+    else last_loadavg_usec -= dt;
+
+    // --------------------------------------------------------------------
+
+    if(likely(do_all_processes)) {
+        if(unlikely(!processes_chart)) {
+            processes_chart = rrdset_find_byname("system.active_processes");
+            if(unlikely(!processes_chart)) {
+                processes_chart = rrdset_create("system", "active_processes", NULL, "processes", NULL, "System Active Processes", "processes", 750, update_every, RRDSET_TYPE_LINE);
+                rrddim_add(processes_chart, "active", NULL, 1, 1, RRDDIM_ABSOLUTE);
+            }
+        }
+        else rrdset_next(processes_chart);
+
+        rrddim_set(processes_chart, "active", active_processes);
+        rrdset_done(processes_chart);
+    }
+
+    return 0;
+}
diff --git a/src/freebsd_stat.c b/src/freebsd_stat.c
new file mode 100644 (file)
index 0000000..1ed513c
--- /dev/null
@@ -0,0 +1,254 @@
+#include "common.h"
+#include <sys/vmmeter.h>
+
+int do_proc_stat(int update_every, unsigned long long dt) {
+    (void)dt;
+
+    static int do_cpu = -1, do_cpu_cores = -1, do_interrupts = -1, do_context = -1, do_forks = -1, do_processes = -1;
+
+    if(unlikely(do_cpu == -1)) {
+        do_cpu          = config_get_boolean("plugin:proc:/proc/stat", "cpu utilization", 1);
+        do_cpu_cores    = config_get_boolean("plugin:proc:/proc/stat", "per cpu core utilization", 1);
+        do_interrupts   = config_get_boolean("plugin:proc:/proc/stat", "cpu interrupts", 1);
+        do_context      = config_get_boolean("plugin:proc:/proc/stat", "context switches", 1);
+        do_forks        = config_get_boolean("plugin:proc:/proc/stat", "processes started", 1);
+        do_processes    = config_get_boolean("plugin:proc:/proc/stat", "processes running", 1);
+    }
+    
+    RRDSET *st;
+
+    char cpuid[5] = "cpu0";
+    unsigned long long user = 0, nice = 0, system = 0, interrupt = 0, idle = 0;
+    u_int vm_stat;
+    size_t intrcnt_size;
+    unsigned long nintr = 0;
+    unsigned long *intrcnt;
+    unsigned long long totalintr = 0;
+    unsigned long long running = 0 , blocked = 0;
+    
+    long multiplier = 1;
+    long divisor = 1; // sysconf(_SC_CLK_TCK);
+    
+    long cp_time[CPUSTATES];
+    long *pcpu_cp_time;
+    
+    int i, ncpus;
+    
+    struct vmtotal total;
+    
+    if(likely(do_cpu)) {
+        if (unlikely(CPUSTATES != 5)) {
+            error("There are %d CPU states (5 was expected)", CPUSTATES);
+            do_cpu = 0;
+            error("Total CPU utilization stats was switched off");
+            return 0;
+        }
+        if (unlikely(GETSYSCTL("kern.cp_time", cp_time))) {
+            do_cpu = 0;
+            error("Total CPU utilization stats was switched off");
+            return 0;
+        }
+        user = cp_time[0];
+        nice = cp_time[1];
+        system = cp_time[2];
+        interrupt = cp_time[3];
+        idle = cp_time[4];
+
+        st = rrdset_find_bytype("system", "cpu");
+        if(unlikely(!st)) {
+            st = rrdset_create("system", "cpu", NULL, "cpu", "system.cpu", "Total CPU utilization", "percentage", 100, update_every, RRDSET_TYPE_STACKED);
+
+            rrddim_add(st, "user", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+            rrddim_add(st, "system", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+            rrddim_add(st, "interrupt", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+            rrddim_add(st, "nice", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+            rrddim_add(st, "idle", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+            rrddim_hide(st, "idle");
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "user", user);
+        rrddim_set(st, "system", system);
+        rrddim_set(st, "interrupt", interrupt);
+        rrddim_set(st, "nice", nice);
+        rrddim_set(st, "idle", idle);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+    
+    if(likely(do_cpu_cores)) {
+        if (unlikely(CPUSTATES != 5)) {
+            error("There are %d CPU states (5 was expected)", CPUSTATES);
+            do_cpu_cores = 0;
+            error("CPU cores utilization stats was switched off");
+            return 0;
+        }
+        if (unlikely(GETSYSCTL("kern.smp.cpus", ncpus))) {
+            do_cpu_cores = 0;
+            error("CPU cores utilization stats was switched off");
+            return 0;
+        }
+        pcpu_cp_time = malloc(sizeof(cp_time) * ncpus);
+        
+        for (i = 0; i < ncpus; i++) {            
+            if (unlikely(getsysctl("kern.cp_times", pcpu_cp_time, sizeof(cp_time) * ncpus))) {
+                do_cpu_cores = 0;
+                error("CPU cores utilization stats was switched off");
+                return 0;
+            }
+            cpuid[3] = '0' + i;
+            user = pcpu_cp_time[i * 5 + 0];
+            nice = pcpu_cp_time[i * 5 + 1];
+            system = pcpu_cp_time[i * 5 + 2];
+            interrupt = pcpu_cp_time[i * 5 + 3];
+            idle = pcpu_cp_time[i * 5 + 4];
+
+            st = rrdset_find_bytype("cpu", cpuid);
+            if(unlikely(!st)) {
+                st = rrdset_create("cpu", cpuid, NULL, "utilization", "cpu.cpu", "Core utilization", "percentage", 1000, update_every, RRDSET_TYPE_STACKED);
+
+                rrddim_add(st, "user", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+                rrddim_add(st, "system", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+                rrddim_add(st, "interrupt", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);            
+                rrddim_add(st, "nice", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+                rrddim_add(st, "idle", NULL, multiplier, divisor, RRDDIM_PCENT_OVER_DIFF_TOTAL);
+                rrddim_hide(st, "idle");
+            }
+            else rrdset_next(st);
+
+            rrddim_set(st, "user", user);
+            rrddim_set(st, "system", system);
+            rrddim_set(st, "interrupt", interrupt);        
+            rrddim_set(st, "nice", nice);        
+            rrddim_set(st, "idle", idle);
+            rrdset_done(st);
+        }
+        free(pcpu_cp_time);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(likely(do_interrupts)) {
+        if (unlikely(sysctlbyname("hw.intrcnt", NULL, &intrcnt_size, NULL, 0) == -1)) {
+            error("sysctl(hw.intrcnt...) failed: %s", strerror(errno));
+            do_interrupts = 0;
+            error("Total device interrupts stats was switched off");
+            return 0;
+        }
+        nintr = intrcnt_size / sizeof(u_long);
+        intrcnt = malloc(nintr * sizeof(u_long));
+        if (unlikely(getsysctl("hw.intrcnt", intrcnt, nintr * sizeof(u_long)))){
+            do_interrupts = 0;
+            error("Total device interrupts stats was switched off");
+            return 0;
+        }
+        for (i = 0; i < nintr; i++)
+            totalintr += intrcnt[i];
+        free(intrcnt);
+
+        st = rrdset_find_bytype("system", "intr");
+        if(unlikely(!st)) {
+            st = rrdset_create("system", "intr", NULL, "interrupts", NULL, "Total Device Interrupts", "interrupts/s", 900, update_every, RRDSET_TYPE_LINE);
+            st->isdetail = 1;
+
+            rrddim_add(st, "interrupts", NULL, 1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "interrupts", totalintr);
+        rrdset_done(st);
+    }
+
+/* Temporarily switched off
+    if(likely(do_interrupts)) {
+        if (unlikely(GETSYSCTL("vm.stats.sys.v_intr", vm_stat))) {
+            do_interrupts = 0;
+            error("Device interrupts utilization stats was switched off");
+            return 0;
+        }
+
+        st = rrdset_find_bytype("system", "intr");
+        if(unlikely(!st)) {
+            st = rrdset_create("system", "intr", NULL, "interrupts", NULL, "Device Interrupts", "interrupts/s", 900, update_every, RRDSET_TYPE_LINE);
+            st->isdetail = 1;
+
+            rrddim_add(st, "interrupts", NULL, 1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "interrupts", vm_stat);
+        rrdset_done(st);
+    }
+*/
+    // --------------------------------------------------------------------
+
+    if(likely(do_context)) {
+        if (unlikely(GETSYSCTL("vm.stats.sys.v_swtch", vm_stat))) {
+            do_context = 0;
+            error("CPU context switches stats was switched off");
+            return 0;
+        }
+        
+        st = rrdset_find_bytype("system", "ctxt");
+        if(unlikely(!st)) {
+            st = rrdset_create("system", "ctxt", NULL, "processes", NULL, "CPU Context Switches", "context switches/s", 800, update_every, RRDSET_TYPE_LINE);
+
+            rrddim_add(st, "switches", NULL, 1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "switches", vm_stat);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(likely(do_forks)) {
+        if (unlikely(GETSYSCTL("vm.stats.vm.v_forks", vm_stat))) {
+            do_forks = 0;
+            error("Fork stats was switched off");
+            return 0;
+        }
+        
+        st = rrdset_find_bytype("system", "forks");
+        if(unlikely(!st)) {
+            st = rrdset_create("system", "forks", NULL, "processes", NULL, "Started Processes", "processes/s", 700, update_every, RRDSET_TYPE_LINE);
+            st->isdetail = 1;
+
+            rrddim_add(st, "started", NULL, 1, 1, RRDDIM_INCREMENTAL);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "started", vm_stat);
+        rrdset_done(st);
+    }
+
+    // --------------------------------------------------------------------
+
+    if(likely(do_processes)) {
+        if (unlikely(GETSYSCTL("vm.vmtotal", total))) {
+            do_processes = 0;
+            error("System processes stats was switched off");
+            return 0;
+        }
+        
+        running = total.t_rq;
+        blocked = total.t_dw + total.t_pw;
+        
+        st = rrdset_find_bytype("system", "processes");
+        if(unlikely(!st)) {
+            st = rrdset_create("system", "processes", NULL, "processes", NULL, "System Processes", "processes", 600, update_every, RRDSET_TYPE_LINE);
+
+            rrddim_add(st, "running", NULL, 1, 1, RRDDIM_ABSOLUTE);
+            rrddim_add(st, "blocked", NULL, -1, 1, RRDDIM_ABSOLUTE);
+        }
+        else rrdset_next(st);
+
+        rrddim_set(st, "running", running);
+        rrddim_set(st, "blocked", blocked);
+        rrdset_done(st);
+    }
+
+    return 0;
+}
\ No newline at end of file
index 99d03e6bc7bb9b12528e4fe6a3419e1038ffe6b9..fab7799c70aadd297c0f1c1e8c99a394d520226e 100644 (file)
@@ -48,7 +48,7 @@ struct netdata_static_thread {
 #ifndef __FreeBSD__    
     {"proc",               "plugins",   "proc",       1, NULL, NULL, proc_main},
 #else
-    {"freebsd",               "plugins",   "freebsd",       1, NULL, NULL, freebsd_main},
+    {"proc",               "plugins",   "proc",       1, NULL, NULL, freebsd_main},
 #endif /* __FreeBSD__ */
     
     {"cgroups",            "plugins",   "cgroups",    1, NULL, NULL, cgroups_main},
index 834d7b72cc34e38c3481df5d3cc298debb68356f..818accedd93553f1ff73c23c2bfe8c176e5890e8 100644 (file)
@@ -42,7 +42,8 @@ void *freebsd_main(void *ptr)
     int vdo_sys_kernel_mm_ksm       = !config_get_boolean("plugin:proc", "/sys/kernel/mm/ksm", 1);
     */
     int vdo_cpu_netdata             = !config_get_boolean("plugin:proc", "netdata server resources", 1);
-
+    int vdo_proc_stat               = !config_get_boolean("plugin:proc", "/proc/stat", 1);
+    int vdo_proc_loadavg            = !config_get_boolean("plugin:proc", "/proc/loadavg", 1);
 
     // keep track of the time each module was called
     /*
@@ -67,6 +68,8 @@ void *freebsd_main(void *ptr)
     unsigned long long sutime_ipc = 0ULL;
     unsigned long long sutime_sys_kernel_mm_ksm = 0ULL;
     */
+    unsigned long long sutime_proc_stat = 0ULL;
+    unsigned long long sutime_proc_loadavg = 0ULL;
 
     unsigned long long step = rrd_update_every * 1000000ULL;
     for(;;) {
@@ -243,7 +246,23 @@ void *freebsd_main(void *ptr)
             sutime_proc_net_rpc_nfs = now;
         }
         if(unlikely(netdata_exit)) break;
-       */
+        */
+        
+        if(!vdo_proc_stat) {
+            debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_stat().");
+            now = time_usec();
+            vdo_proc_stat = do_proc_stat(rrd_update_every, (sutime_proc_stat > 0)?now - sutime_proc_stat:0ULL);
+            sutime_proc_stat = now;
+        }
+        if(unlikely(netdata_exit)) break;
+
+        if(!vdo_proc_loadavg) {
+            debug(D_PROCNETDEV_LOOP, "PROCNETDEV: calling do_proc_loadavg().");
+            now = time_usec();
+            vdo_proc_loadavg = do_proc_loadavg(rrd_update_every, (sutime_proc_loadavg > 0)?now - sutime_proc_loadavg:0ULL);
+            sutime_proc_loadavg = now;
+        }
+        if(unlikely(netdata_exit)) break;
 
         // END -- the job is done
 
@@ -260,3 +279,20 @@ void *freebsd_main(void *ptr)
     pthread_exit(NULL);
     return NULL;
 }
+
+int getsysctl(const char *name, void *ptr, size_t len)
+{
+    size_t nlen = len;
+
+    if (unlikely(sysctlbyname(name, ptr, &nlen, NULL, 0) == -1)) {
+        error("FREEBSD: sysctl(%s...) failed: %s\n", name,
+            strerror(errno));
+        return 1;
+    }
+    if (unlikely(nlen != len)) {
+        error("FREEBSD: sysctl(%s...) expected %lu, got %lu\n",
+            name, (unsigned long)len, (unsigned long)nlen);
+        return 1;
+    }
+    return 0;
+}
\ No newline at end of file
index 6607a28823a1b1dd487915bf9125d41375244fb0..6279683eb3927150de2fef855cc1a90219b29823 100644 (file)
@@ -1,8 +1,12 @@
 #ifndef NETDATA_PLUGIN_FREEBSD_H
 #define NETDATA_PLUGIN_FREEBSD_H 1
 
+#define GETSYSCTL(name, var) getsysctl(name, &(var), sizeof(var))
+
 void *freebsd_main(void *ptr);
 
+extern int getsysctl(const char *name, void *ptr, size_t len);
+
 /*
 extern int do_proc_net_dev(int update_every, unsigned long long dt);
 extern int do_proc_diskstats(int update_every, unsigned long long dt);
@@ -11,7 +15,6 @@ extern int do_proc_net_snmp6(int update_every, unsigned long long dt);
 extern int do_proc_net_netstat(int update_every, unsigned long long dt);
 extern int do_proc_net_stat_conntrack(int update_every, unsigned long long dt);
 extern int do_proc_net_ip_vs_stats(int update_every, unsigned long long dt);
-extern int do_proc_stat(int update_every, unsigned long long dt);
 extern int do_proc_meminfo(int update_every, unsigned long long dt);
 extern int do_proc_vmstat(int update_every, unsigned long long dt);
 extern int do_proc_net_rpc_nfs(int update_every, unsigned long long dt);
@@ -24,5 +27,7 @@ extern int do_proc_loadavg(int update_every, unsigned long long dt);
 extern int do_proc_net_stat_synproxy(int update_every, unsigned long long dt);
 extern int do_proc_net_softnet_stat(int update_every, unsigned long long dt);
 */
+extern int do_proc_stat(int update_every, unsigned long long dt);
+extern int do_proc_loadavg(int update_every, unsigned long long dt);
 
 #endif /* NETDATA_FREEBSD_PROC_H */