From 7a1a310029637d9ef5c5b9cad028f2bf9837f982 Mon Sep 17 00:00:00 2001 From: Pavel Rochnyack Date: Mon, 7 Mar 2016 12:47:14 +0700 Subject: [PATCH] xencpu plugin: Plugin to collect CPU load under Xen Fixed remarks of code review: * Removed static pointer initialization * Tabs replaced by spaces * Added check for xenctrl.h * Changed order of libraries check, added argument quotes * Added plugin documentation --- configure.ac | 48 +++++++++++++++ src/Makefile.am | 7 +++ src/collectd.conf.in | 1 + src/collectd.conf.pod | 8 +++ src/xencpu.c | 163 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 227 insertions(+) create mode 100644 src/xencpu.c diff --git a/configure.ac b/configure.ac index 68db42b1..57135952 100644 --- a/configure.ac +++ b/configure.ac @@ -4709,6 +4709,46 @@ then fi # }}} +# --with-libxenctrl {{{ +with_libxenctrl_cppflags="" +with_libxenctrl_ldflags="" +AC_ARG_WITH(libxenctrl, [AS_HELP_STRING([--with-libxenctrl@<:@=PREFIX@:>@], [Path to libxenctrl.])], +[ + if test "x$withval" != "xno" && test "x$withval" != "xyes" + then + with_libxenctrl_cppflags="-I$withval/include" + with_libxenctrl_ldflags="-L$withval/lib" + with_libxenctrl="yes" + else + with_libxenctrl="$withval" + fi +], +[ + with_libxenctrl="yes" +]) +if test "x$with_libxenctrl" = "xyes" +then + SAVE_CPPFLAGS="$CPPFLAGS" + CPPFLAGS="$CPPFLAGS $with_libxenctrl_cppflags" + + AC_CHECK_HEADERS(xenctrl.h, [with_libxenctrl="yes"], [with_libxenctrl="no (xenctrl.h not found)"]) + + CPPFLAGS="$SAVE_CPPFLAGS" +fi +if test "x$with_libxenctrl" = "xyes" +then + SAVE_CPPFLAGS="$CPPFLAGS" + SAVE_LDFLAGS="$LDFLAGS" + CPPFLAGS="$CPPFLAGS $with_libxenctrl_cppflags" + LDFLAGS="$LDFLAGS $with_libxenctrl_ldflags" + + #Xen versions older than 3.4 has no xc_getcpuinfo() + AC_CHECK_LIB(xenctrl, xc_getcpuinfo, [with_libxenctrl="yes"], [with_libxenctrl="no (symbol 'xc_getcpuinfo' not found)"], []) + + CPPFLAGS="$SAVE_CPPFLAGS" + LDFLAGS="$SAVE_LDFLAGS" +fi + # --with-libxmms {{{ with_xmms_config="xmms-config" with_xmms_cflags="" @@ -5407,6 +5447,7 @@ plugin_virt="no" plugin_vmem="no" plugin_vserver="no" plugin_wireless="no" +plugin_xencpu="no" plugin_zfs_arc="no" plugin_zone="no" plugin_zookeeper="no" @@ -5738,6 +5779,10 @@ then plugin_virt="yes" fi +if test "x$with_libxenctrl" = "xyes" +then + plugin_xencpu="yes" +fi m4_divert_once([HELP_ENABLE], [ collectd plugins:]) @@ -5893,6 +5938,7 @@ AC_PLUGIN([write_redis], [$with_libhiredis], [Redis output plugin AC_PLUGIN([write_riemann], [$with_riemann_c], [Riemann output plugin]) AC_PLUGIN([write_sensu], [yes], [Sensu output plugin]) AC_PLUGIN([write_tsdb], [yes], [TSDB output plugin]) +AC_PLUGIN([xencpu], [$plugin_xencpu], [Xen Host CPU usage]) AC_PLUGIN([xmms], [$with_libxmms], [XMMS statistics]) AC_PLUGIN([zfs_arc], [$plugin_zfs_arc], [ZFS ARC statistics]) AC_PLUGIN([zone], [$plugin_zone], [Solaris container statistics]) @@ -6144,6 +6190,7 @@ Configuration: libupsclient . . . . $with_libupsclient libvarnish . . . . . $with_libvarnish libvirt . . . . . . . $with_libvirt + libxenctrl . . . . . $with_libxenctrl libxml2 . . . . . . . $with_libxml2 libxmms . . . . . . . $with_libxmms libyajl . . . . . . . $with_libyajl @@ -6293,6 +6340,7 @@ Configuration: write_riemann . . . . $enable_write_riemann write_sensu . . . . . $enable_write_sensu write_tsdb . . . . . $enable_write_tsdb + xencpu . . . . . . . $enable_xencpu xmms . . . . . . . . $enable_xmms zfs_arc . . . . . . . $enable_zfs_arc zone . . . . . . . . $enable_zone diff --git a/src/Makefile.am b/src/Makefile.am index 1e3dfbaa..3683b559 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1277,6 +1277,13 @@ write_tsdb_la_SOURCES = write_tsdb.c write_tsdb_la_LDFLAGS = $(PLUGIN_LDFLAGS) endif +if BUILD_PLUGIN_XENCPU +pkglib_LTLIBRARIES += xencpu.la +xencpu_la_SOURCES = xencpu.c +xencpu_la_LDFLAGS = $(PLUGIN_LDFLAGS) +xencpu_la_LIBADD = -lxenctrl +endif + if BUILD_PLUGIN_XMMS pkglib_LTLIBRARIES += xmms.la xmms_la_SOURCES = xmms.c diff --git a/src/collectd.conf.in b/src/collectd.conf.in index 41d10ee3..80a7db9d 100644 --- a/src/collectd.conf.in +++ b/src/collectd.conf.in @@ -206,6 +206,7 @@ #@BUILD_PLUGIN_WRITE_RIEMANN_TRUE@LoadPlugin write_riemann #@BUILD_PLUGIN_WRITE_SENSU_TRUE@LoadPlugin write_sensu #@BUILD_PLUGIN_WRITE_TSDB_TRUE@LoadPlugin write_tsdb +#@BUILD_PLUGIN_XENCPU_TRUE@LoadPlugin xencpu #@BUILD_PLUGIN_XMMS_TRUE@LoadPlugin xmms #@BUILD_PLUGIN_ZFS_ARC_TRUE@LoadPlugin zfs_arc #@BUILD_PLUGIN_ZONE_TRUE@LoadPlugin zone diff --git a/src/collectd.conf.pod b/src/collectd.conf.pod index 3f2b2eff..c72d64a2 100644 --- a/src/collectd.conf.pod +++ b/src/collectd.conf.pod @@ -8077,6 +8077,14 @@ attribute for each metric being sent out to I. =back +=head2 Plugin C + +This plugin collects metrics of hardware CPU load for machine running Xen +hypervisor. Load is calculated from 'idle time' value, provided by Xen. +Result is reported using the C type, for each CPU (core). + +This plugin doesn't have any options (yet). + =head2 Plugin C The I will collect statistics from a I server diff --git a/src/xencpu.c b/src/xencpu.c new file mode 100644 index 00000000..2b872350 --- /dev/null +++ b/src/xencpu.c @@ -0,0 +1,163 @@ +/** + * collectd - src/xencpu.c + * Copyright (C) 2016 Pavel Rochnyak + * + * 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: + * Pavel Rochnyak + **/ + +#include "collectd.h" +#include "common.h" +#include "plugin.h" + +#include + +#ifdef XENCTRL_HAS_XC_INTERFACE + +//Xen-4.1+ +#define XC_INTERFACE_INIT_ARGS NULL,NULL,0 +xc_interface *xc_handle; + +#else /* XENCTRL_HAS_XC_INTERFACE */ + +//For xen-3.4/xen-4.0 +#include +#define xc_strerror(xc_interface, errcode) strerror(errcode) +#define XC_INTERFACE_INIT_ARGS +typedef int xc_interface; +xc_interface xc_handle = 0; + +#endif /* XENCTRL_HAS_XC_INTERFACE */ + +uint32_t num_cpus = 0; +xc_cpuinfo_t *cpu_info; +static value_to_rate_state_t *cpu_states; + +static int xencpu_init (void) +{ + xc_handle = xc_interface_open(XC_INTERFACE_INIT_ARGS); + if (!xc_handle) + { + ERROR ("xencpu: xc_interface_open() failed"); + return (-1); + }; + + xc_physinfo_t *physinfo; + + physinfo = calloc(1, sizeof(xc_physinfo_t)); + if (physinfo == NULL) + { + ERROR ("xencpu plugin: calloc() for physinfo failed."); + xc_interface_close(xc_handle); + return (ENOMEM); + } + + if (xc_physinfo(xc_handle, physinfo) < 0) + { + ERROR ("xencpu plugin: xc_physinfo() failed"); + xc_interface_close(xc_handle); + free(physinfo); + return (-1); + }; + + num_cpus = physinfo->nr_cpus; + free(physinfo); + + INFO ("xencpu plugin: Found %"PRIu32" processors.", num_cpus); + + cpu_info = calloc(num_cpus, sizeof(xc_cpuinfo_t)); + if (cpu_info == NULL) + { + ERROR ("xencpu plugin: calloc() for num_cpus failed."); + xc_interface_close(xc_handle); + return (ENOMEM); + } + + cpu_states = calloc (num_cpus, sizeof (value_to_rate_state_t)); + if (cpu_states == NULL) + { + ERROR ("xencpu plugin: calloc() for cpu_states failed."); + xc_interface_close(xc_handle); + free(cpu_info); + return (ENOMEM); + } + + return (0); +} /* static int xencpu_init */ + +static int xencpu_shutdown (void) +{ + free(cpu_states); + free(cpu_info); + xc_interface_close(xc_handle); + + return 0; +} /* static int xencpu_shutdown */ + +static void submit_value (int cpu_num, gauge_t percent) +{ + value_t values[1]; + value_list_t vl = VALUE_LIST_INIT; + + values[0].gauge = percent; + + vl.values = values; + vl.values_len = 1; + + sstrncpy (vl.host, hostname_g, sizeof (vl.host)); + sstrncpy (vl.plugin, "xencpu", sizeof (vl.plugin)); + sstrncpy (vl.type, "percent", sizeof (vl.type)); + sstrncpy (vl.type_instance, "load", sizeof (vl.type_instance)); + + if (cpu_num >= 0) { + ssnprintf (vl.plugin_instance, sizeof (vl.plugin_instance), + "%i", cpu_num); + } + plugin_dispatch_values (&vl); +} /* static void submit_value */ + +static int xencpu_read (void) +{ + cdtime_t now = cdtime (); + + int rc, nr_cpus; + + rc = xc_getcpuinfo(xc_handle, num_cpus, cpu_info, &nr_cpus); + if (rc < 0) { + ERROR ("xencpu: xc_getcpuinfo() Failed: %d %s\n", rc, xc_strerror(xc_handle,errno)); + return (-1); + } + + int cpu, status; + for (cpu = 0; cpu < nr_cpus; cpu++) { + gauge_t rate = NAN; + value_t value = {.derive = cpu_info[cpu].idletime}; + + status = value_to_rate (&rate, value, DS_TYPE_DERIVE, now, &cpu_states[cpu]); + if (status == 0) { + submit_value(cpu, 100 - rate/10000000); + } + } + + return (0); +} /* static int xencpu_read */ + +void module_register (void) +{ + plugin_register_init ("xencpu", xencpu_init); + plugin_register_read ("xencpu", xencpu_read); + plugin_register_shutdown ("xencpu", xencpu_shutdown); +} /* void module_register */ -- 2.11.0