lpar plugin: Refactor reading of "shared partitions".
authorFlorian Forster <octo@leeloo.lan.home.verplant.org>
Fri, 3 Sep 2010 09:05:37 +0000 (11:05 +0200)
committerFlorian Forster <octo@leeloo.lan.home.verplant.org>
Fri, 3 Sep 2010 09:05:37 +0000 (11:05 +0200)
Especially calculating the ticks unavailable to the partition has been
improved. The "pool statistics" may need some further work.

The code has been written without an AIX machine at hand, so it's
absolutely untested and may not even compile. Sorry.

src/lpar.c

index ef1fa59..2f40691 100644 (file)
 #include "collectd.h"
 #include "common.h"
 #include "plugin.h"
+
 #include <sys/protosw.h>
 #include <libperfstat.h>
 #include <sys/utsname.h>
 
-#ifndef XINTFRAC
-# include <sys/systemcfg.h>
-# define XINTFRAC ((double)(_system_configuration.Xint) / \
-                   (double)(_system_configuration.Xfrac))
-#endif
-#define HTIC2SEC(x)    ((double)x * XINTFRAC / 1000000000.0)
-
-/* Max length of the type instance string */
-#define TYPE_INST_LEN (sizeof("pool--total") + 2*sizeof(int) + 1)
-
 static const char *config_keys[] =
 {
   "CpuPoolStats",
@@ -46,11 +37,6 @@ static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
 static _Bool pool_stats = 0;
 static _Bool report_by_serial = 0;
 
-static u_longlong_t last_time_base;
-static u_longlong_t ent_counter;
-static _Bool donate_flag = 0;
-
-
 static int lpar_config (const char *key, const char *value)
 {
        if (strcasecmp ("CpuPoolStats", key) == 0)
@@ -75,38 +61,7 @@ static int lpar_config (const char *key, const char *value)
        return (0);
 } /* int lpar_config */
 
-static int lpar_init (void)
-{
-       perfstat_partition_total_t lparstats;
-
-       /* Retrieve the initial metrics */
-       if (!perfstat_partition_total (NULL, &lparstats,
-                                      sizeof (perfstat_partition_total_t), 1))
-       {
-               ERROR ("lpar plugin: perfstat_partition_total failed.");
-               return (-1);
-       }
-
-       if (!lparstats.type.b.shared_enabled && lparstats.type.b.donate_enabled)
-       {
-               donate_flag = 1;
-       }
-
-       if (pool_stats && !lparstats.type.b.pool_util_authority)
-       {
-               WARNING ("lpar plugin: this system does not have pool authority. "
-                       "Disabling CPU pool statistics collection.");
-               pool_stats = 0;
-       }
-
-       /* Initialize the fake counter for entitled capacity */
-       last_time_base = lparstats.timebase_last;
-       ent_counter = 0;
-
-       return (0);
-} /* int lpar_init */
-
-static void lpar_submit (const char *type_instance, double value)
+static void lpar_submit (const char *type_instance, counter_t value)
 {
        value_t values[1];
        value_list_t vl = VALUE_LIST_INIT;
@@ -116,7 +71,7 @@ static void lpar_submit (const char *type_instance, double value)
           integer part is very small and the resulting graphs get blocky. We regain
           some precision by applying a x100 factor before casting it to a counter,
           turning the final value into CPU units instead of CPUs. */
-       values[0].counter = (counter_t)(value * 100.0 + 0.5);
+       values[0].counter = value;
 
        vl.values = values;
        vl.values_len = 1;
@@ -146,9 +101,104 @@ static void lpar_submit (const char *type_instance, double value)
        plugin_dispatch_values (&vl);
 }
 
+static int lpar_read_shared_partition (const perfstat_partition_total_t *data)
+{
+       static counter_t time_old;
+       static counter_t user_old;
+       static counter_t syst_old;
+       static counter_t wait_old;
+       static counter_t idle_old;
+       static counter_t unav_old;
+
+       counter_t user = (counter_t) data->puser;
+       counter_t syst = (counter_t) data->psys;
+       counter_t wait = (counter_t) data->pwait;
+       counter_t idle = (counter_t) data->pidle;
+       counter_t unav = 0;
+
+       /*
+        * On a shared partition, we're "entitled" to a certain amount of
+        * processing power, for example 250/100 of a physical CPU. Processing
+        * capacity not used by the partition may be assigned to a different
+        * partition by the hypervisor, so "idle" is hopefully a very small
+        * number.
+        *
+        * We calculate the amount of ticks assigned to a different partition
+        * from the number of ticks we're entitled to and the number of ticks
+        * we used up.
+        */
+       if (time_old != 0)
+       {
+               counter_t time_diff;
+               counter_t entitled_ticks;
+               counter_t consumed_ticks;
+               counter_t user_diff;
+               counter_t syst_diff;
+               counter_t wait_diff;
+               counter_t idle_diff;
+               counter_t unav_diff;
+
+               double entitled_pool_capacity;
+
+               /* Number of ticks since we last run. */
+               time_diff = ((counter_t) data->timebase_last) - time_old;
+
+               /* entitled_pool_capacity is in 1/100th of a CPU */
+               entitled_pool_capacity = 0.01 * ((double) data->entitled_pool_capacity);
+
+               /* The number of ticks this partition would have been entitled to. */
+               entitled_ticks = (counter_t) ((entitled_pool_capacity * ((double) time_diff)) + .5);
+
+               /* The number of ticks actually spent in the various states */
+               user_diff = user - user_old;
+               syst_diff = syst - syst_old;
+               wait_diff = wait - wait_old;
+               idle_diff = idle - idle_old;
+               consumed_ticks = user_diff + syst_diff + wait_diff + idle_diff;
+
+               if (entitled_ticks >= consumed_ticks)
+                       unav_diff = entitled_ticks - consumed_ticks;
+               else
+                       unav_diff = 0;
+               unav = unav_old + unav_diff;
+
+               lpar_submit ("user", user);
+               lpar_submit ("system", syst);
+               lpar_submit ("wait", wait);
+               lpar_submit ("idle", idle);
+               lpar_submit ("unavailable", unav);
+       }
+
+       time_old = (counter_t) data->timebase_last;
+       user_old = user;
+       syst_old = syst;
+       wait_old = wait;
+       idle_old = idle;
+       unav_old = unav;
+
+       return (0);
+} /* int lpar_read_shared_partition */
+
+static int lpar_read_dedicated_partition (const perfstat_partition_total_t *data)
+{
+       lpar_submit ("user",   (counter_t) data->puser);
+       lpar_submit ("system", (counter_t) data->psys);
+       lpar_submit ("wait",   (counter_t) data->pwait);
+       lpar_submit ("idle",   (counter_t) data->pidle);
+
+       if (data->type.b.donate_enabled)
+       {
+               lpar_submit ("idle_donated", (counter_t) data->idle_donated_purr);
+               lpar_submit ("busy_donated", (counter_t) data->busy_donated_purr);
+               lpar_submit ("idle_stolen",  (counter_t) data->idle_stolen_purr);
+               lpar_submit ("busy_stolen",  (counter_t) data->busy_stolen_purr);
+       }
+
+       return (0);
+} /* int lpar_read_dedicated_partition */
+
 static int lpar_read (void)
 {
-       u_longlong_t delta_time_base;
        perfstat_partition_total_t lparstats;
 
        /* Retrieve the current metrics */
@@ -159,30 +209,21 @@ static int lpar_read (void)
                return (-1);
        }
 
-       delta_time_base = lparstats.timebase_last - last_time_base;
-       last_time_base  = lparstats.timebase_last;
-
-       lpar_submit ("user", HTIC2SEC(lparstats.puser));
-       lpar_submit ("sys",  HTIC2SEC(lparstats.psys));
-       lpar_submit ("wait", HTIC2SEC(lparstats.pwait));
-       lpar_submit ("idle", HTIC2SEC(lparstats.pidle));
-       /* Entitled capacity is reported as an absolute value instead of a counter,
-          so we fake one. It's also in CPU units, hence the division by 100 before
-          submission. */
-       ent_counter += lparstats.entitled_proc_capacity * delta_time_base;
-       lpar_submit ("ent",  HTIC2SEC(ent_counter) / 100.0);
+       if (lparstats.type.b.shared_enabled)
+               lpar_read_shared_partition (&lparstats);
+       else /* if (!shared_enabled) */
+               lpar_read_dedicated_partition (&lparstats);
 
-       if (donate_flag)
+       if (pool_stats && !lparstats.type.b.pool_util_authority)
        {
-               lpar_submit ("idle_donated", HTIC2SEC(lparstats.idle_donated_purr));
-               lpar_submit ("busy_donated", HTIC2SEC(lparstats.busy_donated_purr));
-               lpar_submit ("idle_stolen",  HTIC2SEC(lparstats.idle_stolen_purr));
-               lpar_submit ("busy_stolen",  HTIC2SEC(lparstats.busy_stolen_purr));
+               WARNING ("lpar plugin: This partition does not have pool authority. "
+                               "Disabling CPU pool statistics collection.");
+               pool_stats = 0;
        }
 
        if (pool_stats)
        {
-               char typinst[TYPE_INST_LEN];
+               char typinst[DATA_MAX_NAME_LEN];
 
                /* Pool stats are in CPU x ns */
                ssnprintf (typinst, sizeof(typinst), "pool-%X-busy", lparstats.pool_id);
@@ -199,7 +240,6 @@ void module_register (void)
 {
        plugin_register_config ("lpar", lpar_config,
                                config_keys, config_keys_num);
-       plugin_register_init ("lpar", lpar_init);
        plugin_register_read ("lpar", lpar_read);
 } /* void module_register */