Hello Florian,
here is a new version of my lpar plugin. I tried to address the
shortcomings of the previous attempt:
- Minimum and maximum proc capacity are gone, being static values
- The plugin now uses the cpu type for every value, so there is no need
anymore for the lpar_cpu type
- This also means there is no need anymore to compute rates in the
plugin, so the code is IMHO much more elegant
- There is a config option "ReportBySerial", as described in my previous
email
- We now use pool_busy_time directly instead of computing it from total
and idle
The patch is against the current 4.10 branch, rather than against
ar/lpar, because it is more of a complete rewrite than just fixes. I
could provide a patch against ar/lpar however if you prefer so.
Regards,
Aurélien Reynaud
diff --git a/configure.in b/configure.in
index 75ac706..a928302 100644
--- a/configure.in
+++ b/configure.in
@@ -4292,6 +4292,7 @@ AC_PLUGIN([java], [$with_java], [Embed the Java Virtual Machine])
AC_PLUGIN([libvirt], [$plugin_libvirt], [Virtual machine statistics])
AC_PLUGIN([load], [$plugin_load], [System load])
AC_PLUGIN([logfile], [yes], [File logging plugin])
+AC_PLUGIN([lpar], [$with_perfstat], [AIX logical partitions statistics])
AC_PLUGIN([madwifi], [$have_linux_wireless_h], [Madwifi wireless statistics])
AC_PLUGIN([match_empty_counter], [yes], [The empty counter match])
AC_PLUGIN([match_hashed], [yes], [The hashed match])
@@ -4609,6 +4610,7 @@ Configuration:
libvirt . . . . . . . $enable_libvirt
load . . . . . . . . $enable_load
logfile . . . . . . . $enable_logfile
+ lpar... . . . . . . . $enable_lpar
madwifi . . . . . . . $enable_madwifi
match_empty_counter . $enable_match_empty_counter
match_hashed . . . . $enable_match_hashed
diff --git a/src/Makefile.am b/src/Makefile.am
index c6b0538..3bf4184 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -499,6 +499,15 @@ collectd_LDADD += "-dlopen" logfile.la
collectd_DEPENDENCIES += logfile.la
endif
+if BUILD_PLUGIN_LPAR
+pkglib_LTLIBRARIES += lpar.la
+lpar_la_SOURCES = lpar.c
+lpar_la_LDFLAGS = -module -avoid-version
+collectd_LDADD += "-dlopen" lpar.la
+collectd_DEPENDENCIES += lpar.la
+lpar_la_LIBADD = -lperfstat
+endif
+
if BUILD_PLUGIN_MADWIFI
pkglib_LTLIBRARIES += madwifi.la
madwifi_la_SOURCES = madwifi.c madwifi.h
diff --git a/src/lpar.c b/src/lpar.c
new file mode 100755
index 0000000..2267e03
--- /dev/null
+++ b/src/lpar.c
@@ -0,0 +1,202 @@
+/**
+ * collectd - src/lpar.c
+ * Copyright (C) 2010 Aurélien Reynaud
+ *
+ * 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
+ * Free Software Foundation; only version 2 of the License is applicable.
+ *
+ * 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
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Authors:
+ * Aurelien Reynaud <collectd at wattapower.net>
+ **/
+
+#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",
+ "ReportBySerial"
+};
+static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
+static int pool_stats = 0,
+ report_by_serial = 0;
+
+static u_longlong_t last_time_base;
+static u_longlong_t ent_counter;
+static int donate_flag = 0;
+
+
+static int lpar_config (const char *key, const char *value)
+{
+ if (strcasecmp ("CpuPoolStats", key) == 0)
+ {
+ if (IS_TRUE (value))
+ pool_stats = 1;
+ }
+ else if (strcasecmp ("ReportBySerial", key) == 0)
+ {
+ if (IS_TRUE (value))
+ report_by_serial = 1;
+ }
+ else
+ {
+ return (-1);
+ }
+
+ 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)
+{
+ value_t values[1];
+ value_list_t vl = VALUE_LIST_INIT;
+
+ /* Although it appears as a double, value is really a (scaled) counter,
+ expressed in CPU x seconds. At high collection rates (< 1 min), its
+ 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);
+
+ vl.values = values;
+ vl.values_len = 1;
+
+ /* An LPAR has the same serial number as the physical system it is currently
+ running on. It is a convenient way of tracking LPARs as they are moved
+ from chassis to chassis through Live Partition Mobility (LPM). */
+ if (report_by_serial)
+ {
+ struct utsname name;
+ if (uname (&name) != 0)
+ {
+ ERROR ("lpar plugin: uname failed.");
+ return;
+ }
+ sstrncpy (vl.host, name.machine, sizeof (vl.host));
+ sstrncpy (vl.plugin_instance, hostname_g, sizeof (vl.plugin));
+ }
+ else
+ {
+ sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+ }
+ sstrncpy (vl.plugin, "lpar", sizeof (vl.plugin));
+ sstrncpy (vl.type, "cpu", sizeof (vl.type));
+ sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+
+ plugin_dispatch_values (&vl);
+}
+
+static int lpar_read (void)
+{
+ u_longlong_t delta_time_base;
+ perfstat_partition_total_t lparstats;
+
+ /* Retrieve the current metrics */
+ if (!perfstat_partition_total (NULL, &lparstats,
+ sizeof (perfstat_partition_total_t), 1))
+ {
+ ERROR ("lpar plugin: perfstat_partition_total failed.");
+ 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 (donate_flag)
+ {
+ 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));
+ }
+
+ if (pool_stats)
+ {
+ char typinst[TYPE_INST_LEN];
+
+ /* Pool stats are in CPU x ns */
+ ssnprintf (typinst, sizeof(typinst), "pool-%X-busy", lparstats.pool_id);
+ lpar_submit (typinst, (double)lparstats.pool_busy_time / 1000000000.0);
+
+ ssnprintf (typinst, sizeof(typinst), "pool-%X-total", lparstats.pool_id);
+ lpar_submit (typinst, (double)lparstats.pool_max_time / 1000000000.0);
+ }
+
+ return (0);
+} /* int lpar_read */
+
+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 */
+
+/* vim: set sw=2 sts=2 ts=8 : */
+
_______________________________________________
collectd mailing list
[email protected]
http://mailman.verplant.org/listinfo/collectd