hugepages plugin: a stats plugin for hugepages
authorJaroslav Safka <jaroslavx.safka@intel.com>
Thu, 23 Jun 2016 04:53:12 +0000 (05:53 +0100)
committerMaryam Tahhan <maryam.tahhan@intel.com>
Mon, 18 Jul 2016 12:07:05 +0000 (13:07 +0100)
Plugin that allows stats for hugepages to be collected.

Change-Id: Ide5ff31c54206cf5ee3d6155899bd53e8edae7bd
Signed-off-by: Jaroslav Safka <jaroslavx.safka@intel.com>
Signed-off-by: Kim Jones <kim-marie.jones@intel.com>
Signed-off-by: Maryam Tahhan <maryam.tahhan@intel.com>
README
configure.ac
src/Makefile.am
src/collectd.conf.in
src/collectd.conf.pod
src/hugepages.c [new file with mode: 0644]
src/types.db

diff --git a/README b/README
index 1c3af7a..1693c75 100644 (file)
--- a/README
+++ b/README
@@ -128,6 +128,12 @@ Features
     - hddtemp
       Hard disk temperatures using hddtempd.
 
+    - hugepages
+      Report the total number of hugpages, the number of free/reserved
+      hugepages, and the size of the available hugepages. More info on
+      hugepages can be found here:
+      https://www.kernel.org/doc/Documentation/vm/hugetlbpage.txt.
+
     - interface
       Interface traffic: Number of octets, packets and errors for each
       interface.
index c69842c..a69f16b 100644 (file)
@@ -482,6 +482,9 @@ fi
 # For hddtemp module
 AC_CHECK_HEADERS(linux/major.h)
 
+# For hugepages module
+AC_CHECK_HEADERS(dirent.h)
+
 # For md module (Linux only)
 if test "x$ac_system" = "xLinux"
 then
@@ -5971,6 +5974,7 @@ AC_PLUGIN([fscache],             [$plugin_fscache],         [fscache statistics]
 AC_PLUGIN([gmond],               [$with_libganglia],        [Ganglia plugin])
 AC_PLUGIN([grpc],                [$with_grpc],              [gRPC plugin])
 AC_PLUGIN([hddtemp],             [yes],                     [Query hddtempd])
+AC_PLUGIN([hugepages],           [yes],                     [Hugepages statistics])
 AC_PLUGIN([interface],           [$plugin_interface],       [Interface traffic statistics])
 AC_PLUGIN([ipc],                 [$plugin_ipc],             [IPC statistics])
 AC_PLUGIN([ipmi],                [$plugin_ipmi],            [IPMI sensor statistics])
@@ -6382,6 +6386,7 @@ AC_MSG_RESULT([    fscache . . . . . . . $enable_fscache])
 AC_MSG_RESULT([    gmond . . . . . . . . $enable_gmond])
 AC_MSG_RESULT([    grpc  . . . . . . . . $enable_grpc])
 AC_MSG_RESULT([    hddtemp . . . . . . . $enable_hddtemp])
+AC_MSG_RESULT([    hugepages . . . . . . $enable_hugepages])
 AC_MSG_RESULT([    interface . . . . . . $enable_interface])
 AC_MSG_RESULT([    ipc . . . . . . . . . $enable_ipc])
 AC_MSG_RESULT([    ipmi  . . . . . . . . $enable_ipmi])
index 641e2fa..0cc7e1c 100644 (file)
@@ -442,6 +442,13 @@ hddtemp_la_LIBADD += -lsocket
 endif
 endif
 
+if BUILD_PLUGIN_HUGEPAGES
+pkglib_LTLIBRARIES += hugepages.la
+hugepages_la_SOURCES = hugepages.c
+hugepages_la_LDFLAGS = $(PLUGIN_LDFLAGS)
+hugepages_la_LIBADD =
+endif
+
 if BUILD_PLUGIN_INTERFACE
 pkglib_LTLIBRARIES += interface.la
 interface_la_SOURCES = interface.c
index 54072d0..2b57a68 100644 (file)
 #@BUILD_PLUGIN_GMOND_TRUE@LoadPlugin gmond
 #@BUILD_PLUGIN_GRPC_TRUE@LoadPlugin grpc
 #@BUILD_PLUGIN_HDDTEMP_TRUE@LoadPlugin hddtemp
+#@BUILD_PLUGIN_HUGEPAGES_TRUE@LoadPlugin hugepages
 @BUILD_PLUGIN_INTERFACE_TRUE@@BUILD_PLUGIN_INTERFACE_TRUE@LoadPlugin interface
 #@BUILD_PLUGIN_IPC_TRUE@LoadPlugin ipc
 #@BUILD_PLUGIN_IPMI_TRUE@LoadPlugin ipmi
 #  Port "7634"
 #</Plugin>
 
+#<Plugin hugepages>
+#    EnableNuma "true"
+#    EnableMM "true"
+#</Plugin>
+
 #<Plugin interface>
 #      Interface "eth0"
 #      IgnoreSelected false
index 37a4d6b..0a7bd01 100644 (file)
@@ -2699,6 +2699,26 @@ TCP-Port to connect to. Defaults to B<7634>.
 
 =back
 
+=head2 Plugin C<hugepages>
+
+To get values from B<hugepages> collectd read directories
+"/sys/devices/system/node/*/hugepages" and
+"/sys/kernel/mm/hugepages"
+Reading of these directories can be disabled by following
+options. Default is enabled.
+
+=over 4
+
+=item B<EnableNuma> I<true>|I<false>
+
+Enable/Disable reading stats in "/sys/devices/system/node/*/hugepages"
+
+=item B<EnableMM> I<true>|I<false>
+
+Enable/Disable reading stats in "/sys/kernel/mm/hugepages"
+
+=back
+
 =head2 Plugin C<interface>
 
 =over 4
diff --git a/src/hugepages.c b/src/hugepages.c
new file mode 100644 (file)
index 0000000..db18de0
--- /dev/null
@@ -0,0 +1,286 @@
+/*-
+ * collectd - src/hugepages.c
+ * MIT License
+ *
+ * Copyright(c) 2016 Intel Corporation. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *   Jaroslav Safka <jaroslavx.safka@intel.com>
+ */
+
+#include "collectd.h"
+#include "common.h" /* auxiliary functions */
+#include "plugin.h" /* plugin_register_*, plugin_dispatch_values */
+
+#include <stdio.h>
+#include <string.h>
+#include <dirent.h>
+
+static int huge_read (void);
+static int huge_config_callback (const char *key, const char *val);
+
+static const char PLUGIN_NAME[] = "hugepages";
+static const char SYS_NODE[] = "/sys/devices/system/node";
+static const char NODE[] = "node";
+static const char HUGEPAGES_DIR[] = "hugepages";
+static const char SYS_NODE_HUGEPAGES[] = "/sys/devices/system/node/%s/hugepages";
+static const char SYS_MM_HUGEPAGES[] = "/sys/kernel/mm/hugepages";
+static const char CONFIG_NAME[] = "hugepages";
+static const char CFG_ENA_NUMA[] = "EnableNuma";
+static const char CFG_ENA_MM[] = "EnableMM";
+
+static const char *CONFIG_KEYS[] = {
+  CFG_ENA_NUMA,
+  CFG_ENA_MM,
+};
+static const size_t CONFIG_KEYS_NUM = sizeof(CONFIG_KEYS)/sizeof(*CONFIG_NAME);
+static int g_config_ena_numa = 1;
+static int g_config_ena_mm = 1;
+
+static int huge_config_callback (const char *key, const char *val)
+{
+  INFO("HugePages config key='%s', val='%s'", key, val);
+
+  if (0 == strcasecmp(key, CFG_ENA_NUMA)) {
+    g_config_ena_numa = IS_TRUE(val);
+    return 0;
+  }
+  if (0 == strcasecmp(key, CFG_ENA_MM)) {
+    g_config_ena_mm = IS_TRUE(val);
+    return 0;
+  }
+
+  return -1;
+}
+
+static void submit_one (const char *plug_inst, const char *type,
+  const char *type_instance, derive_t value)
+{
+  value_t values[1];
+  value_list_t vl = VALUE_LIST_INIT;
+
+  values[0].derive = value;
+
+  vl.values = values;
+  vl.values_len = 1;
+  sstrncpy (vl.host, hostname_g, sizeof (vl.host));
+  sstrncpy (vl.plugin, PLUGIN_NAME, sizeof (vl.plugin));
+  sstrncpy (vl.plugin_instance, plug_inst, sizeof (vl.plugin_instance));
+  sstrncpy (vl.type, type, sizeof (vl.type));
+
+  if (type_instance != NULL) {
+    sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
+  }
+
+  DEBUG("submit_one pl_inst:%s, inst_type %s, type %s, val=%lu",
+      plug_inst, type_instance, type, value);
+
+  plugin_dispatch_values (&vl);
+}
+
+static int read_hugepage_entry(const char *path, const char* entry,
+    const char* plinst, const char* hpsize)
+{
+  char path2[512];
+  long value = 0;
+  snprintf(path2, sizeof(path2), "%s/%s", path, entry);
+
+  FILE *fh = fopen(path2, "rt");
+  if (NULL == fh) {
+    ERROR("Cannot open %s", path2);
+    return -1;
+  }
+
+  if (fscanf(fh, "%ld", &value) !=1) {
+    ERROR("Cannot parse file %s", path2);
+    fclose(fh);
+    return -1;
+  }
+
+  submit_one (plinst, entry, hpsize, value);
+
+  fclose(fh);
+  return 0;
+}
+
+static int read_syshugepage_dir(const char* path, const char* dirhpsize,
+    const char* node)
+{
+  DIR       *dir = NULL;
+  struct dirent *entry = NULL;
+  struct dirent *result = NULL;
+  size_t name_max = 0;
+  size_t len = 0;
+
+  dir = opendir(path);
+  if (NULL == dir) {
+    ERROR("Cannot open directory %s", path);
+    return -1;
+  }
+
+  name_max = pathconf(path, _PC_NAME_MAX);
+  if (name_max == -1) {    /* Limit not defined, or error */
+    name_max = 255;     /* Take a guess */
+  }
+
+  len = offsetof(struct dirent, d_name) + name_max + 1;
+  entry = malloc(len);
+  if (entry == NULL) {
+    ERROR("Malloc returned NULL");
+    return -1;
+  }
+
+  while (0 == readdir_r(dir, entry, &result)) {
+    if (NULL == result) {
+      /* end of dir */
+      break;
+    }
+    if (result->d_name[0] == '.') {
+      /* not interesting "." and ".." */
+      continue;
+    }
+
+    read_hugepage_entry(path, result->d_name, node, dirhpsize);
+  }
+
+  free(entry);
+  closedir(dir);
+
+
+  return 0;
+}
+
+static int read_syshugepages(const char* path, const char* node)
+{
+  DIR       *dir = NULL;
+  struct dirent *entry = NULL;
+  struct dirent *result = NULL;
+  size_t name_max = 0;
+  size_t len = 0;
+  char path2[255];
+
+  dir = opendir(path);
+  if (NULL == dir) {
+    ERROR("Cannot open directory %s", path);
+    return -1;
+  }
+
+  name_max = pathconf(path, _PC_NAME_MAX);
+  if (name_max == -1) {    /* Limit not defined, or error */
+    name_max = 255;     /* Take a guess */
+  }
+  len = offsetof(struct dirent, d_name) + name_max + 1;
+  entry = malloc(len);
+  if (entry == NULL) {
+    ERROR("Malloc returned NULL");
+    return -1;
+  }
+
+  while (0 == readdir_r(dir, entry, &result)) {
+    /* read "hugepages-XXXXXkB" entries */
+    if (NULL == result) {
+      /* end of dir */
+      break;
+    }
+
+    if (strncmp(result->d_name, HUGEPAGES_DIR, sizeof(HUGEPAGES_DIR)-1)) {
+      /* not node dir */
+      continue;
+    }
+
+    /* /sys/devices/system/node/node?/hugepages/ */
+    snprintf(path2, sizeof(path2), "%s/%s", path, result->d_name);
+    read_syshugepage_dir(path2, result->d_name, node);
+  }
+
+  free(entry);
+  closedir(dir);
+
+  return 0;
+}
+
+static int read_nodes(void)
+{
+  DIR       *dir = NULL;
+  struct dirent *entry = NULL;
+  struct dirent *result = NULL;
+  size_t name_max = 0;
+  size_t len = 0;
+  char path[255];
+
+  dir = opendir(SYS_NODE);
+  if (NULL == dir) {
+    ERROR("Cannot open directory %s", SYS_NODE);
+    return -1;
+  }
+
+  name_max = pathconf(SYS_NODE, _PC_NAME_MAX);
+  if (name_max == -1) {    /* Limit not defined, or error */
+    name_max = 255;     /* Take a guess */
+  }
+  len = offsetof(struct dirent, d_name) + name_max + 1;
+  entry = malloc(len);
+  if (entry == NULL) {
+    ERROR("Malloc returned NULL");
+    return -1;
+  }
+
+  while (0 == readdir_r(dir, entry, &result)) {
+    if (NULL == result) {
+      /* end of dir */
+      break;
+    }
+
+    if (strncmp(result->d_name, NODE, sizeof(NODE)-1)) {
+      /* not node dir */
+      continue;
+    }
+
+    snprintf(path, sizeof(path), SYS_NODE_HUGEPAGES, result->d_name);
+    read_syshugepages(path, result->d_name);
+  }
+
+  free(entry);
+  closedir(dir);
+
+  return 0;
+}
+
+
+static int huge_read (void)
+{
+  if (g_config_ena_mm) {
+    read_syshugepages(SYS_MM_HUGEPAGES, "mm");
+  }
+  if (g_config_ena_numa) {
+    read_nodes();
+  }
+
+  return 0;
+}
+
+void module_register (void)
+{
+       plugin_register_config(CONFIG_NAME, huge_config_callback, CONFIG_KEYS,
+                         CONFIG_KEYS_NUM);
+  plugin_register_read (PLUGIN_NAME, huge_read);
+}
+
index 77a9d06..8a1581a 100644 (file)
@@ -82,6 +82,7 @@ file_size               value:GAUGE:0:U
 files                   value:GAUGE:0:U
 flow                    value:GAUGE:0:U
 fork_rate               value:DERIVE:0:U
+free_hugepages          value:DERIVE:0:U
 frequency               value:GAUGE:0:U
 frequency_error         value:GAUGE:-2:2 
 frequency_offset        value:GAUGE:-1000000:1000000
@@ -148,6 +149,9 @@ node_octets             rx:DERIVE:0:U, tx:DERIVE:0:U
 node_rssi               value:GAUGE:0:255
 node_stat               value:DERIVE:0:U
 node_tx_rate            value:GAUGE:0:127
+nr_overcommit_hugepages value:DERIVE:0:U
+nr_hugepages            value:DERIVE:0:U
+nr_hugepages_mempolicy  value:DERIVE:0:U
 objects                 value:GAUGE:0:U
 operations              value:DERIVE:0:U
 packets                 value:DERIVE:0:U
@@ -191,6 +195,7 @@ records                 value:GAUGE:0:U
 requests                value:GAUGE:0:U
 response_code           value:GAUGE:0:U
 response_time           value:GAUGE:0:U
+resv_hugepages          value:DERIVE:0:U
 root_delay              value:GAUGE:U:U
 root_dispersion         value:GAUGE:U:U
 route_etx               value:GAUGE:0:U
@@ -210,6 +215,7 @@ snr                     value:GAUGE:0:U
 spam_check              value:GAUGE:0:U
 spam_score              value:GAUGE:U:U
 spl                     value:GAUGE:U:U
+surplus_hugepages       value:DERIVE:0:U
 swap                    value:GAUGE:0:1099511627776
 swap_io                 value:DERIVE:0:U
 tcp_connections         value:GAUGE:0:4294967295