{GPL, other}: Relicense to MIT license.
[collectd.git] / src / cpu.c
index 1d7322c..e3de4bd 100644 (file)
--- a/src/cpu.c
+++ b/src/cpu.c
@@ -1,9 +1,9 @@
 /**
  * collectd - src/cpu.c
  * Copyright (C) 2005-2010  Florian octo Forster
- * Copyright (C) 2008       Oleg King
- * Copyright (C) 2009       Simon Kuhnle
- * Copyright (C) 2009       Manuel Sanmartin
+ * Copyright (C) 2008      Oleg King
+ * Copyright (C) 2009      Simon Kuhnle
+ * Copyright (C) 2009      Manuel Sanmartin
  *
  * 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
@@ -11,7 +11,7 @@
  *
  * 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
+ * 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
@@ -19,7 +19,7 @@
  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  *
  * Authors:
- *   Florian octo Forster <octo at verplant.org>
+ *   Florian octo Forster <octo at collectd.org>
  *   Oleg King <king2 at kaluga.ru>
  *   Simon Kuhnle <simon at blarzwurst.de>
  *   Manuel Sanmartin
 # define CAN_USE_SYSCTL 0
 #endif
 
-#define CPU_SUBMIT_USER 1
-#define CPU_SUBMIT_SYSTEM 2
-#define CPU_SUBMIT_WAIT 3
-#define CPU_SUBMIT_NICE 4
-#define CPU_SUBMIT_SWAP 5
-#define CPU_SUBMIT_INTERRUPT 6
-#define CPU_SUBMIT_SOFTIRQ 7
-#define CPU_SUBMIT_STEAL 8
-#define CPU_SUBMIT_IDLE 9
-#define CPU_SUBMIT_ACTIVE 10
-#define CPU_SUBMIT_MAX 11
-#define CPU_SUBMIT_FLUSH -1
+#define CPU_SUBMIT_USER 0
+#define CPU_SUBMIT_SYSTEM 1
+#define CPU_SUBMIT_WAIT 2
+#define CPU_SUBMIT_NICE 3
+#define CPU_SUBMIT_SWAP 4
+#define CPU_SUBMIT_INTERRUPT 5
+#define CPU_SUBMIT_SOFTIRQ 6
+#define CPU_SUBMIT_STEAL 7
+#define CPU_SUBMIT_IDLE 8
+#define CPU_SUBMIT_ACTIVE 9
+#define CPU_SUBMIT_MAX 10
 
 #if HAVE_STATGRAB_H
 # include <statgrab.h>
 #endif
 
 static const char *cpu_state_names[] = {
-       "none",
        "user",
        "system",
        "wait",
@@ -134,8 +132,8 @@ static mach_msg_type_number_t cpu_list_len;
 
 #if PROCESSOR_TEMPERATURE
 static int cpu_temp_retry_counter = 0;
-static int cpu_temp_retry_step    = 1;
-static int cpu_temp_retry_max     = 1;
+static int cpu_temp_retry_step   = 1;
+static int cpu_temp_retry_max    = 1;
 #endif /* PROCESSOR_TEMPERATURE */
 /* #endif PROCESSOR_CPU_LOAD_INFO */
 
@@ -172,10 +170,14 @@ static int numcpu;
 static int pnumcpu;
 #endif /* HAVE_PERFSTAT */
 
-static gauge_t percents[CPU_SUBMIT_MAX] = {
-        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+static value_to_rate_state_t *percents = NULL;
+static gauge_t agg_percents[CPU_SUBMIT_MAX] = {
+       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+
 };
-int cpu_count = 0;
+static int percents_cells = 0;
+static int cpu_count = 0;
+
 
 static _Bool report_by_cpu = 1;
 static _Bool report_percent = 0;
@@ -184,11 +186,12 @@ static _Bool report_active = 0;
 static const char *config_keys[] =
 {
        "ReportByCpu",
-        "ReportActive",
+       "ReportActive",
        "ValuesPercentage"
 };
 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
 
+
 static int cpu_config (const char *key, const char *value)
 {
        if (strcasecmp (key, "ReportByCpu") == 0) {
@@ -196,13 +199,58 @@ static int cpu_config (const char *key, const char *value)
                if (!report_by_cpu)
                        report_percent = 1;
        }
-       if (strcasecmp (key, "ValuesPercentage") == 0)
+       if (strcasecmp (key, "ValuesPercentage") == 0) {
                report_percent = IS_TRUE (value) ? 1 : 0;
-        if (strcasecmp (key, "ReportActive") == 0)
-                report_active = IS_TRUE (value) ? 1 : 0;
+               if (!report_percent)
+                       report_by_cpu = 1;
+       }
+       if (strcasecmp (key, "ReportActive") == 0)
+               report_active = IS_TRUE (value) ? 1 : 0;
        return (-1);
 }
 
+static int cpu_states_grow (void)
+{
+  void *tmp;
+  int size;
+  int i;
+
+  size = cpu_count * CPU_SUBMIT_MAX; /* always alloc for all states */
+
+  if (size <= 0)
+         return 0;
+
+  if (percents_cells >= size)
+         return 0;
+
+  if (percents == NULL) {
+         percents = malloc(size * sizeof(*percents));
+         if (percents == NULL)
+                 return -1;
+         for (i = 0; i < size; i++)
+                 memset(&percents[i], 0, sizeof(*percents));
+         percents_cells = size;
+         return 0;
+  }
+
+  tmp = realloc(percents, size * sizeof(*percents));
+
+  if (tmp == NULL) {
+         ERROR ("cpu plugin: could not reserve enough space to hold states");
+         percents = NULL;
+         return -1;
+  }
+
+  percents = tmp;
+
+  for (i = percents_cells ; i < size; i++)
+         memset(&percents[i], 0, sizeof(*percents));
+
+  percents_cells = size;
+  return 0;
+} /* cpu_states_grow */
+
+
 static int init (void)
 {
 #if PROCESSOR_CPU_LOAD_INFO || PROCESSOR_TEMPERATURE
@@ -304,10 +352,10 @@ static void submit_value (int cpu_num, int cpu_state, const char *type, value_t
        value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
 
-        memcpy(&values[0], &value, sizeof(value));
+       memcpy(&values[0], &value, sizeof(value));
 
-        vl.values = values;
-        vl.values_len = 1;
+       vl.values = values;
+       vl.values_len = 1;
 
        sstrncpy (vl.host, hostname_g, sizeof (vl.host));
        sstrncpy (vl.plugin, "cpu", sizeof (vl.plugin));
@@ -324,46 +372,47 @@ static void submit_value (int cpu_num, int cpu_state, const char *type, value_t
 
 static void submit_percent(int cpu_num, int cpu_state, gauge_t percent)
 {
-        value_t value;
+       value_t value;
 
-        value.gauge = percent;
-        submit_value (cpu_num, cpu_state, "percent", value);
+       value.gauge = percent;
+       submit_value (cpu_num, cpu_state, "percent", value);
 }
 
 static void submit_derive(int cpu_num, int cpu_state, derive_t derive)
 {
-        value_t value;
+       value_t value;
 
-        value.derive = derive;
-        submit_value (cpu_num, cpu_state, "cpu", value);
+       value.derive = derive;
+       submit_value (cpu_num, cpu_state, "cpu", value);
 }
 
 static void submit_flush (void)
 {
-        int i = 0;
-
-        if (report_by_cpu)
-                return;
-
-        for (i = 1; i < CPU_SUBMIT_MAX; i++) {
-                if (percents[i] == -1)
-                        continue;
-                submit_percent (-1, i, percents[i] / cpu_count);
-        }
-        cpu_count = 0;
-        memset(percents, 0, sizeof(percents));
+       int i = 0;
+
+       if (report_by_cpu) {
+               cpu_count = 0;
+               return;
+       }
+
+       for (i = 0; i < CPU_SUBMIT_MAX; i++) {
+               if (agg_percents[i] == -1)
+                       continue;
+
+               submit_percent(-1, i, agg_percents[i] / cpu_count);
+               agg_percents[i] = -1;
+       }
+       cpu_count = 0;
 }
 
 static void submit (int cpu_num, derive_t *derives)
 {
 
        int i = 0;
-       derive_t cpu_active = 0;
-       derive_t cpu_total = 0;
-        gauge_t percent;
-        
+
        if (!report_percent && report_by_cpu) {
-               for (i = 1; i < CPU_SUBMIT_ACTIVE; i++)
+               derive_t cpu_active = 0;
+               for (i = 0; i < CPU_SUBMIT_ACTIVE; i++)
                {
                        if (derives[i] == -1)
                                continue;
@@ -373,37 +422,63 @@ static void submit (int cpu_num, derive_t *derives)
 
                        submit_derive(cpu_num, i, derives[i]);
                }
-                if (report_active)
-                        submit_derive(cpu_num, CPU_SUBMIT_ACTIVE, cpu_active);
+               if (report_active)
+                       submit_derive(cpu_num, CPU_SUBMIT_ACTIVE, cpu_active);
        }
        else /* we are reporting percents */
        {
-               for (i = 1; i < CPU_SUBMIT_ACTIVE; i++) {
+               cdtime_t cdt;
+               gauge_t percent;
+               gauge_t cpu_total = 0;
+               gauge_t cpu_active = 0;
+               gauge_t local_rates[CPU_SUBMIT_MAX];
+
+               cpu_count++;
+               if (cpu_states_grow())
+                       return;
+
+               memset(local_rates, 0, sizeof(local_rates));
+
+               cdt = cdtime();
+               for (i = 0; i < CPU_SUBMIT_ACTIVE; i++) {
+                       value_t rate;
+                       int index;
+
                        if (derives[i] == -1)
                                continue;
-                       cpu_total += derives[i];
+
+                       index = (cpu_num * CPU_SUBMIT_MAX) + i;
+                       if (value_to_rate(&rate, derives[i], &percents[index],
+                                         DS_TYPE_DERIVE, cdt) != 0) {
+                               local_rates[i] = -1;
+                               continue;
+                       }
+
+                       local_rates[i] = rate.gauge;
+                       cpu_total += rate.gauge;
                        if (i != CPU_SUBMIT_IDLE)
-                               cpu_active += derives[i];
+                               cpu_active += rate.gauge;
                }
-                if (report_active)
-                        derives[CPU_SUBMIT_ACTIVE] = cpu_active;
-                else
-                        derives[CPU_SUBMIT_ACTIVE] = -1;
+               if (cpu_total == 0.0)
+                       return;
 
-               cpu_count++;
-               for (i = 1; i < CPU_SUBMIT_MAX; i++) {
-                       if (derives[i] == -1) {
-                               percents[i] = -1;
+               if (report_active)
+                       local_rates[CPU_SUBMIT_ACTIVE] = cpu_active;
+
+               for (i = 0; i < CPU_SUBMIT_MAX; i++) {
+                       if (local_rates[i] == -1)
                                continue;
-                       }
-                       percent = ((gauge_t)derives[i] / (gauge_t)cpu_total) * 100.0;
 
+                       percent = (local_rates[i] / cpu_total) * 100;
                        if (report_by_cpu)
-                       {
                                submit_percent (cpu_num, i, percent);
-                       } else if (percents[i] != -1) {
-                                percents[i] += percent;
+                       else {
+                               if (agg_percents[i] == -1)
+                                       agg_percents[i] = percent;
+                               else
+                                       agg_percents[i] += percent;
                        }
+
                }
        }
 }
@@ -416,13 +491,12 @@ static int cpu_read (void)
        kern_return_t status;
 
 #if PROCESSOR_CPU_LOAD_INFO
-       derive_t                       cpu_active;
        processor_cpu_load_info_data_t cpu_info;
-       mach_msg_type_number_t         cpu_info_len;
+       mach_msg_type_number_t         cpu_info_len;
 #endif
 #if PROCESSOR_TEMPERATURE
-       processor_info_data_t          cpu_temp;
-       mach_msg_type_number_t         cpu_temp_len;
+       processor_info_data_t          cpu_temp;
+       mach_msg_type_number_t         cpu_temp_len;
 #endif
 
        host_t cpu_host;
@@ -430,9 +504,9 @@ static int cpu_read (void)
        for (cpu = 0; cpu < cpu_list_len; cpu++)
        {
 #if PROCESSOR_CPU_LOAD_INFO
-                derive_t derives[CPU_SUBMIT_MAX] = {
-                        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1      
-                };
+               derive_t derives[CPU_SUBMIT_MAX] = {
+                       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+               };
                memset(derives, -1, sizeof(derives));
                cpu_host = 0;
                cpu_info_len = PROCESSOR_BASIC_INFO_COUNT;
@@ -451,10 +525,10 @@ static int cpu_read (void)
                        continue;
                }
 
-               derives[CPU_USER] = (derive_t) cpu_info.cpu_ticks[CPU_STATE_USER];
-               derives[CPU_NICE] = (derive_t) cpu_info.cpu_ticks[CPU_STATE_NICE];
-               derives[CPU_SYSTEM] = (derive_t) cpu_info.cpu_ticks[CPU_STATE_SYSTEM];
-               derives[CPU_IDLE] = (derive_t) cpu_info.cpu_ticks[CPU_STATE_IDLE];
+               derives[CPU_SUBMIT_USER] = (derive_t) cpu_info.cpu_ticks[CPU_STATE_USER];
+               derives[CPU_SUBMIT_NICE] = (derive_t) cpu_info.cpu_ticks[CPU_STATE_NICE];
+               derives[CPU_SUBMIT_SYSTEM] = (derive_t) cpu_info.cpu_ticks[CPU_STATE_SYSTEM];
+               derives[CPU_SUBMIT_IDLE] = (derive_t) cpu_info.cpu_ticks[CPU_STATE_IDLE];
                submit (cpu, derives);
 
 #endif /* PROCESSOR_CPU_LOAD_INFO */
@@ -493,7 +567,7 @@ static int cpu_read (void)
                if (cpu_temp_len != 1)
                {
                        DEBUG ("processor_info (PROCESSOR_TEMPERATURE) returned %i elements..?",
-                                       (int) cpu_temp_len);
+                                       (int) cpu_temp_len);
                        continue;
                }
 
@@ -501,7 +575,7 @@ static int cpu_read (void)
                cpu_temp_retry_step    = 1;
 #endif /* PROCESSOR_TEMPERATURE */
        }
-        submit_flush ();
+       submit_flush ();
 /* #endif PROCESSOR_CPU_LOAD_INFO */
 
 #elif defined(KERNEL_LINUX)
@@ -522,10 +596,10 @@ static int cpu_read (void)
 
        while (fgets (buf, 1024, fh) != NULL)
        {
-                derive_t derives[CPU_SUBMIT_MAX] = {
-                        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1      
-                };
-                
+               derive_t derives[CPU_SUBMIT_MAX] = {
+                       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+               };
+
                if (strncmp (buf, "cpu", 3))
                        continue;
                if ((buf[3] < '0') || (buf[3] > '9'))
@@ -552,7 +626,7 @@ static int cpu_read (void)
                }
                submit(cpu, derives);
        }
-        submit_flush();
+       submit_flush();
 
        fclose (fh);
 /* #endif defined(KERNEL_LINUX) */
@@ -566,10 +640,10 @@ static int cpu_read (void)
 
        for (cpu = 0; cpu < numcpu; cpu++)
        {
-                derive_t derives[CPU_SUBMIT_MAX] = {
-                        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1      
-                };
-                
+               derive_t derives[CPU_SUBMIT_MAX] = {
+                       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+               };
+
                if (kstat_read (kc, ksp[cpu], &cs) == -1)
                        continue; /* error message? */
 
@@ -580,7 +654,7 @@ static int cpu_read (void)
                derives[CPU_SUBMIT_WAIT] = cs.cpu_sysinfo.cpu[CPU_WAIT];
                submit (ksp[cpu]->ks_instance, derives);
        }
-        submit_flush ();
+       submit_flush ();
 /* #endif defined(HAVE_LIBKSTAT) */
 
 #elif CAN_USE_SYSCTL
@@ -639,10 +713,10 @@ static int cpu_read (void)
        }
 
        for (i = 0; i < numcpu; i++) {
-                derive_t derives[CPU_SUBMIT_MAX] = {
-                        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1      
-                };
-                
+               derive_t derives[CPU_SUBMIT_MAX] = {
+                       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+               };
+
                derives[CPU_SUBMIT_USER] = cpuinfo[i][CP_USER];
                derives[CPU_SUBMIT_NICE] = cpuinfo[i][CP_NICE];
                derives[CPU_SUBMIT_SYSTEM] = cpuinfo[i][CP_SYS];
@@ -650,7 +724,7 @@ static int cpu_read (void)
                derives[CPU_SUBMIT_INTERRUPT] = cpuinfo[i][CP_INTR];
                submit(i, derives);
        }
-        submit_flush();
+       submit_flush();
 /* #endif CAN_USE_SYSCTL */
 #elif defined(HAVE_SYSCTLBYNAME) && defined(HAVE_SYSCTL_KERN_CP_TIMES)
        long cpuinfo[maxcpu][CPUSTATES];
@@ -669,26 +743,26 @@ static int cpu_read (void)
        }
 
        for (i = 0; i < numcpu; i++) {
-                derive_t derives[CPU_SUBMIT_MAX] = {
-                        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1      
-                };
+               derive_t derives[CPU_SUBMIT_MAX] = {
+                       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+               };
 
                derives[CPU_SUBMIT_USER] = cpuinfo[i][CP_USER];
                derives[CPU_SUBMIT_NICE] = cpuinfo[i][CP_NICE];
                derives[CPU_SUBMIT_SYSTEM] = cpuinfo[i][CP_SYS];
                derives[CPU_SUBMIT_IDLE] = cpuinfo[i][CP_IDLE];
                derives[CPU_SUBMIT_INTERRUPT] = cpuinfo[i][CP_INTR];
-                submit(i, derives);
+               submit(i, derives);
        }
-        submit_flush();
+       submit_flush();
 
 /* #endif HAVE_SYSCTL_KERN_CP_TIMES */
 #elif defined(HAVE_SYSCTLBYNAME)
        long cpuinfo[CPUSTATES];
        size_t cpuinfo_size;
-        derive_t derives[CPU_SUBMIT_MAX] = {
-                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1      
-        };
+       derive_t derives[CPU_SUBMIT_MAX] = {
+               -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+       };
 
        cpuinfo_size = sizeof (cpuinfo);
 
@@ -700,21 +774,21 @@ static int cpu_read (void)
                return (-1);
        }
 
-        derives[CPU_SUBMIT_USER] = cpuinfo[CP_USER];
-        derives[CPU_SUBMIT_SYSTEM] = cpuinfo[CP_SYS];
-        derives[CPU_SUBMIT_NICE] = cpuinfo[CP_NICE];
-        derives[CPU_SUBMIT_IDLE] = cpuinfo[CP_IDLE];
-        derives[CPU_SUBMIT_INTERRUPT] = cpuinfo[CP_INTR];
+       derives[CPU_SUBMIT_USER] = cpuinfo[CP_USER];
+       derives[CPU_SUBMIT_SYSTEM] = cpuinfo[CP_SYS];
+       derives[CPU_SUBMIT_NICE] = cpuinfo[CP_NICE];
+       derives[CPU_SUBMIT_IDLE] = cpuinfo[CP_IDLE];
+       derives[CPU_SUBMIT_INTERRUPT] = cpuinfo[CP_INTR];
        submit(0, derives);
-        submit_flush();
+       submit_flush();
 
 /* #endif HAVE_SYSCTLBYNAME */
 
 #elif defined(HAVE_LIBSTATGRAB)
        sg_cpu_stats *cs;
-        derive_t derives[CPU_SUBMIT_MAX] = {
-                -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1      
-        };
+       derive_t derives[CPU_SUBMIT_MAX] = {
+               -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+       };
        cs = sg_get_cpu_stats ();
 
        if (cs == NULL)
@@ -729,8 +803,8 @@ static int cpu_read (void)
        derives[CPU_SUBMIT_SYSTEM] = (derive_t) cs->kernel;
        derives[CPU_SUBMIT_USER] = (derive_t) cs->user;
        derives[CPU_SUBMIT_WAIT] = (derive_t) cs->iowait;
-        submit(0, derives);
-        submit_flush();
+       submit(0, derives);
+       submit_flush();
 /* #endif HAVE_LIBSTATGRAB */
 
 #elif defined(HAVE_PERFSTAT)
@@ -765,16 +839,16 @@ static int cpu_read (void)
 
        for (i = 0; i < cpus; i++)
        {
-                derive_t derives[CPU_SUBMIT_MAX] = {
-                        -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1      
-                };
+               derive_t derives[CPU_SUBMIT_MAX] = {
+                       -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+               };
                derives[CPU_SUBMIT_IDLE] = perfcpu[i].idle;
                derives[CPU_SUBMIT_SYSTEM] = perfcpu[i].sys;
                derives[CPU_SUBMIT_USER] = perfcpu[i].user;
                derives[CPU_SUBMIT_WAIT] = perfcpu[i].wait;
-                submit(i, derives);
+               submit(i, derives);
        }
-        submit_flush();
+       submit_flush();
 #endif /* HAVE_PERFSTAT */
 
        return (0);