lpar plugin: rename NS_TO_TICKS() macro to CLOCKTICKS_TO_TICKS()
[collectd.git] / src / lpar.c
index 4f7f444..4d53447 100644 (file)
@@ -34,6 +34,8 @@
                    (double)(_system_configuration.Xfrac))
 #endif
 
+#define CLOCKTICKS_TO_TICKS(cticks) ((cticks) / XINTFRAC)
+
 static const char *config_keys[] =
 {
   "CpuPoolStats",
@@ -43,45 +45,12 @@ static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
 
 static _Bool pool_stats = 0;
 static _Bool report_by_serial = 0;
+#if PERFSTAT_SUPPORTS_DONATION
 static _Bool donate_flag = 0;
+#endif
 static char serial[SYS_NMLN];
 
-static u_longlong_t time_old;
-static u_longlong_t user_old,
-                    syst_old,
-                    idle_old,
-                    wait_old;
-static u_longlong_t pool_busy_time_old,
-                    pool_max_time_old;
-static u_longlong_t idle_donated_old,
-                    busy_donated_old,
-                    busy_stolen_old,
-                    idle_stolen_old;
-
-
-static void save_last_values (perfstat_partition_total_t *lparstats)
-{
-       time_old = lparstats->timebase_last;
-
-       user_old = lparstats->puser;
-       syst_old = lparstats->psys;
-       idle_old = lparstats->pidle;
-       wait_old = lparstats->pwait;
-
-       if (donate_flag)
-       {
-               idle_donated_old = lparstats->idle_donated_purr;
-               busy_donated_old = lparstats->busy_donated_purr;
-               busy_stolen_old  = lparstats->busy_stolen_purr;
-               idle_stolen_old  = lparstats->idle_stolen_purr;
-       }
-
-       if (pool_stats)
-       {
-               pool_busy_time_old = lparstats->pool_busy_time;
-               pool_max_time_old  = lparstats->pool_max_time;
-       }
-} /* void save_last_values */
+static perfstat_partition_total_t lparstats_old;
 
 static int lpar_config (const char *key, const char *value)
 {
@@ -109,12 +78,11 @@ static int lpar_config (const char *key, const char *value)
 
 static int lpar_init (void)
 {
-       perfstat_partition_total_t lparstats;
        int status;
 
        /* Retrieve the initial metrics. Returns the number of structures filled. */
        status = perfstat_partition_total (/* name = */ NULL, /* (must be NULL) */
-                       &lparstats, sizeof (perfstat_partition_total_t),
+                       &lparstats_old, sizeof (perfstat_partition_total_t),
                        /* number = */ 1 /* (must be 1) */);
        if (status != 1)
        {
@@ -125,21 +93,21 @@ static int lpar_init (void)
                return (-1);
        }
 
-       if (!lparstats.type.b.shared_enabled && lparstats.type.b.donate_enabled)
+#if PERFSTAT_SUPPORTS_DONATION
+       if (!lparstats_old.type.b.shared_enabled
+                       && lparstats_old.type.b.donate_enabled)
        {
                donate_flag = 1;
        }
+#endif
 
-       if (pool_stats && !lparstats.type.b.pool_util_authority)
+       if (pool_stats && !lparstats_old.type.b.pool_util_authority)
        {
                WARNING ("lpar plugin: This partition does not have pool authority. "
                                "Disabling CPU pool statistics collection.");
                pool_stats = 0;
        }
 
-       /* Save the initial data */
-       save_last_values (&lparstats);
-
        return (0);
 } /* int lpar_init */
 
@@ -201,50 +169,58 @@ static int lpar_read (void)
                return (-1);
        }
 
+       /* Number of ticks since we last run. */
+       ticks = lparstats.timebase_last - lparstats_old.timebase_last;
+       if (ticks == 0)
+       {
+               /* The stats have not been updated. Return now to avoid
+                * dividing by zero */
+               return (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.
+        *
+        * A dedicated partition may donate its CPUs to another partition and
+        * may steal ticks from somewhere else (another partition or maybe the
+        * shared pool, I don't know --octo).
         */
 
-       /* Number of ticks since we last run. */
-       ticks = lparstats.timebase_last - time_old;
-       if (ticks == 0)
-       {
-               /* The stats have not been updated. Return now to avoid dividing by zero */
-               return (0);
-       }
-
        /* entitled_proc_capacity is in 1/100th of a CPU */
        entitled_proc_capacity = 0.01 * ((double) lparstats.entitled_proc_capacity);
        lpar_submit ("entitled", entitled_proc_capacity);
 
        /* The number of ticks actually spent in the various states */
-       user_ticks = lparstats.puser - user_old;
-       syst_ticks = lparstats.psys  - syst_old;
-       wait_ticks = lparstats.pwait - wait_old;
-       idle_ticks = lparstats.pidle - idle_old;
+       user_ticks = lparstats.puser - lparstats_old.puser;
+       syst_ticks = lparstats.psys  - lparstats_old.psys;
+       wait_ticks = lparstats.pwait - lparstats_old.pwait;
+       idle_ticks = lparstats.pidle - lparstats_old.pidle;
        consumed_ticks = user_ticks + syst_ticks + wait_ticks + idle_ticks;
 
        lpar_submit ("user", (double) user_ticks / (double) ticks);
-       lpar_submit ("sys",  (double) syst_ticks / (double) ticks);
+       lpar_submit ("system", (double) syst_ticks / (double) ticks);
        lpar_submit ("wait", (double) wait_ticks / (double) ticks);
        lpar_submit ("idle", (double) idle_ticks / (double) ticks);
 
+#if PERFSTAT_SUPPORTS_DONATION
        if (donate_flag)
        {
+               /* donated => ticks given to another partition
+                * stolen  => ticks received from another partition */
                u_longlong_t idle_donated_ticks, busy_donated_ticks;
                u_longlong_t idle_stolen_ticks, busy_stolen_ticks;
 
-               idle_donated_ticks = lparstats.idle_donated_purr - idle_donated_old;
-               busy_donated_ticks = lparstats.busy_donated_purr - busy_donated_old;
-               idle_stolen_ticks  = lparstats.idle_stolen_purr  - idle_stolen_old;
-               busy_stolen_ticks  = lparstats.busy_stolen_purr  - busy_stolen_old;
-
                /* FYI:  PURR == Processor Utilization of Resources Register
                 *      SPURR == Scaled PURR */
+               idle_donated_ticks = lparstats.idle_donated_purr - lparstats_old.idle_donated_purr;
+               busy_donated_ticks = lparstats.busy_donated_purr - lparstats_old.busy_donated_purr;
+               idle_stolen_ticks  = lparstats.idle_stolen_purr  - lparstats_old.idle_stolen_purr;
+               busy_stolen_ticks  = lparstats.busy_stolen_purr  - lparstats_old.busy_stolen_purr;
+
                lpar_submit ("idle_donated", (double) idle_donated_ticks / (double) ticks);
                lpar_submit ("busy_donated", (double) busy_donated_ticks / (double) ticks);
                lpar_submit ("idle_stolen",  (double) idle_stolen_ticks  / (double) ticks);
@@ -253,26 +229,34 @@ static int lpar_read (void)
                /* Donated ticks will be accounted for as stolen ticks in other LPARs */
                consumed_ticks += idle_stolen_ticks + busy_stolen_ticks;
        }
+#endif
 
        lpar_submit ("consumed", (double) consumed_ticks / (double) ticks);
 
        if (pool_stats)
        {
                char typinst[DATA_MAX_NAME_LEN];
-               u_longlong_t pool_busy_ns, pool_max_ns;
-
-               pool_busy_ns = lparstats.pool_busy_time - pool_busy_time_old;
-               pool_max_ns  = lparstats.pool_max_time  - pool_max_time_old;
+               u_longlong_t pool_idle_cticks;
+               double pool_idle_cpus;
+               double pool_busy_cpus;
+
+               /* We're calculating "busy" from "idle" and the total number of
+                * CPUs, because the "busy" member didn't exist in early versions
+                * of libperfstat. It was added somewhere between AIX 5.3 ML5 and ML9. */
+               pool_idle_cticks = lparstats.pool_idle_time - lparstats_old.pool_idle_time;
+               pool_idle_cpus = CLOCKTICKS_TO_TICKS ((double) pool_idle_cticks) / (double) ticks;
+               pool_busy_cpus = ((double) lparstats.phys_cpus_pool) - pool_idle_cpus;
+               if (pool_busy_cpus < 0.0)
+                       pool_busy_cpus = 0.0;
 
-               /* Pool stats are in CPU x ns */
                ssnprintf (typinst, sizeof (typinst), "pool-%X-busy", lparstats.pool_id);
-               lpar_submit (typinst, (double) pool_busy_ns / XINTFRAC / (double) ticks);
+               lpar_submit (typinst, pool_busy_cpus);
 
-               ssnprintf (typinst, sizeof (typinst), "pool-%X-total", lparstats.pool_id);
-               lpar_submit (typinst, (double) pool_max_ns / XINTFRAC / (double) ticks);
+               ssnprintf (typinst, sizeof (typinst), "pool-%X-idle", lparstats.pool_id);
+               lpar_submit (typinst, pool_idle_cpus);
        }
 
-       save_last_values (&lparstats);
+       memcpy (&lparstats_old, &lparstats, sizeof (lparstats_old));
 
        return (0);
 } /* int lpar_read */