From: Ruben Kerkhof Date: Mon, 22 Aug 2016 20:35:17 +0000 (+0200) Subject: Merge branch 'hugepages' X-Git-Tag: collectd-5.7.0~119 X-Git-Url: https://git.octo.it/?p=collectd.git;a=commitdiff_plain;h=f876292e5ce4be40ab5b031b2bcfb347f00da1f8;hp=8313250e5fdc28c9f01b5bc94211fe0e7a8f023e Merge branch 'hugepages' --- diff --git a/README b/README index ee909d64..e8f0ca1e 100644 --- a/README +++ b/README @@ -134,6 +134,11 @@ Features - hddtemp Hard disk temperatures using hddtempd. + - hugepages + Report the number of used and free 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. diff --git a/configure.ac b/configure.ac index 9a6da11d..929205bc 100644 --- a/configure.ac +++ b/configure.ac @@ -5709,6 +5709,7 @@ plugin_fhcount="no" plugin_fscache="no" plugin_gps="no" plugin_grpc="no" +plugin_hugepages="no" plugin_interface="no" plugin_ipmi="no" plugin_ipvs="no" @@ -5757,6 +5758,7 @@ then plugin_entropy="yes" plugin_fhcount="yes" plugin_fscache="yes" + plugin_hugepages="yes" plugin_interface="yes" plugin_ipc="yes" plugin_irq="yes" @@ -6163,6 +6165,7 @@ AC_PLUGIN([gmond], [$with_libganglia], [Ganglia plugin]) AC_PLUGIN([gps], [$plugin_gps], [GPS plugin]) AC_PLUGIN([grpc], [$plugin_grpc], [gRPC plugin]) AC_PLUGIN([hddtemp], [yes], [Query hddtempd]) +AC_PLUGIN([hugepages], [$plugin_hugepages], [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]) @@ -6593,6 +6596,7 @@ AC_MSG_RESULT([ gmond . . . . . . . . $enable_gmond]) AC_MSG_RESULT([ gps . . . . . . . . . $enable_gps]) 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]) diff --git a/src/Makefile.am b/src/Makefile.am index dbd5bb91..bc5f4294 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -470,6 +470,12 @@ hddtemp_la_LIBADD += -lsocket endif endif +if BUILD_PLUGIN_HUGEPAGES +pkglib_LTLIBRARIES += hugepages.la +hugepages_la_SOURCES = hugepages.c +hugepages_la_LDFLAGS = $(PLUGIN_LDFLAGS) +endif + if BUILD_PLUGIN_INTERFACE pkglib_LTLIBRARIES += interface.la interface_la_SOURCES = interface.c diff --git a/src/collectd.conf.in b/src/collectd.conf.in index f6898116..16b66482 100644 --- a/src/collectd.conf.in +++ b/src/collectd.conf.in @@ -126,6 +126,7 @@ #@BUILD_PLUGIN_GPS_TRUE@LoadPlugin gps #@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 @@ -594,6 +595,11 @@ # Port "7634" # +# +# ReportPerNodeHP "true" +# ReportRootHP "true" +# + # # Interface "eth0" # IgnoreSelected false diff --git a/src/collectd.conf.pod b/src/collectd.conf.pod index e302e816..d5045c16 100644 --- a/src/collectd.conf.pod +++ b/src/collectd.conf.pod @@ -2813,6 +2813,32 @@ TCP-Port to connect to. Defaults to B<7634>. =back +=head2 Plugin C + +To collect B information, collectd reads directories +"/sys/devices/system/node/*/hugepages" and +"/sys/kernel/mm/hugepages". +Reading of these directories can be disabled by the following +options (default is enabled). + +=over 4 + +=item B I|I + +If enabled, information will be collected from the hugepage +counters in "/sys/devices/system/node/*/hugepages". +This is used to check the per-node hugepage statistics on +a NUMA system. + +=item B I|I + +If enabled, information will be collected from the hugepage +counters in "/sys/kernel/mm/hugepages". +This can be used on both NUMA and non-NUMA systems to check +the overall hugepage statistics. + +=back + =head2 Plugin C =over 4 diff --git a/src/hugepages.c b/src/hugepages.c new file mode 100644 index 00000000..ac9441d0 --- /dev/null +++ b/src/hugepages.c @@ -0,0 +1,290 @@ +/*- + * 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 + * Kim-Marie Jones + */ + +#include "collectd.h" +#include "common.h" /* auxiliary functions */ +#include "plugin.h" /* plugin_register_*, plugin_dispatch_values */ + +static const char g_plugin_name[] = "hugepages"; +static const char g_cfg_rpt_numa[] = "ReportPerNodeHP"; +static const char g_cfg_rpt_mm[] = "ReportRootHP"; + +static const char *g_config_keys[] = { + g_cfg_rpt_numa, + g_cfg_rpt_mm, +}; +static size_t g_config_keys_num = STATIC_ARRAY_SIZE(g_config_keys); +static int g_flag_rpt_numa = 1; +static int g_flag_rpt_mm = 1; + +struct entry_info { + char *d_name; + const char *node; +}; + +static int huge_config_callback(const char *key, const char *val) +{ + DEBUG("%s: HugePages config key='%s', val='%s'", g_plugin_name, key, val); + + if (strcasecmp(key, g_cfg_rpt_numa) == 0) { + g_flag_rpt_numa = IS_TRUE(val); + return 0; + } + if (strcasecmp(key, g_cfg_rpt_mm) == 0) { + g_flag_rpt_mm = IS_TRUE(val); + return 0; + } + + return -1; +} + +static void submit_hp(const char *plug_inst, const char *type, + const char *type_instance, gauge_t free_value, gauge_t used_value) +{ + value_t values[2]; + value_list_t vl = VALUE_LIST_INIT; + + values[0].gauge = free_value; + values[1].gauge = used_value; + + vl.values = values; + vl.values_len = 2; + sstrncpy (vl.host, hostname_g, sizeof (vl.host)); + sstrncpy (vl.plugin, g_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_hp pl_inst:%s, inst_type %s, type %s, free=%lf, used=%lf", + plug_inst, type_instance, type, free_value, used_value); + + plugin_dispatch_values (&vl); +} + +static int read_hugepage_entry(const char *path, const char *entry, + void *e_info) +{ + char path2[PATH_MAX]; + static const char type[] = "hugepages"; + static const char partial_type_inst[] = "free_used"; + char type_instance[PATH_MAX]; + char *strin; + struct entry_info *hpsize_plinst = e_info; + static int flag = 0; + static double used_hp = 0; + static double free_hp = 0; + double value; + + ssnprintf(path2, sizeof(path2), "%s/%s", path, entry); + + FILE *fh = fopen(path2, "rt"); + if (fh == NULL) { + ERROR("%s: cannot open %s", g_plugin_name, path2); + return -1; + } + + if (fscanf(fh, "%lf", &value) !=1) { + ERROR("%s: cannot parse file %s", g_plugin_name, path2); + fclose(fh); + return -1; + } + + if (strcmp(entry, "nr_hugepages") == 0) { + used_hp += value; + flag++; + } else if (strcmp(entry, "surplus_hugepages") == 0) { + used_hp += value; + flag++; + } else if (strcmp(entry, "free_hugepages") == 0) { + used_hp -= value; + free_hp = value; + flag++; + } + + if (flag == 3) { + /* Can now submit "used" and "free" values. + * 0x2D is the ASCII "-" character, after which the string + * contains "kB" + * The string passed as param 3 to submit_hp is of the format: + * --kB + */ + strin = strchr(hpsize_plinst->d_name, 0x2D); + if (strin != NULL) { + ssnprintf(type_instance, sizeof(type_instance), "%s%s", partial_type_inst, strin); + } else { + ssnprintf(type_instance, sizeof(type_instance), "%s%s", partial_type_inst, + hpsize_plinst->d_name); + } + submit_hp(hpsize_plinst->node, type, type_instance, free_hp, used_hp); + + /* Reset for next time */ + flag = 0; + used_hp = 0; + free_hp = 0; + } + + fclose(fh); + return 0; +} + +static int read_syshugepages(const char* path, const char* node) +{ + static const char hugepages_dir[] = "hugepages"; + DIR *dir; + struct dirent *result; + char path2[PATH_MAX]; + struct entry_info e_info; + long lim; + + dir = opendir(path); + if (dir == NULL) { + ERROR("%s: cannot open directory %s", g_plugin_name, path); + return -1; + } + + errno = 0; + if ((lim = pathconf(path, _PC_NAME_MAX)) == -1) { + /* Limit not defined if errno == 0, otherwise error */ + if (errno != 0) { + ERROR("%s: pathconf failed", g_plugin_name); + closedir(dir); + return -1; + } else { + lim = PATH_MAX; + } + } + + /* read "hugepages-XXXXXkB" entries */ + while ((result = readdir(dir)) != NULL) { + if (strncmp(result->d_name, hugepages_dir, sizeof(hugepages_dir)-1)) { + /* not node dir */ + errno = 0; + continue; + } + + /* /sys/devices/system/node/node?/hugepages/ */ + ssnprintf(path2, (size_t) lim, "%s/%s", path, result->d_name); + + e_info.d_name = result->d_name; + e_info.node = node; + walk_directory(path2, read_hugepage_entry, &e_info, 0); + errno = 0; + } + + /* Check if NULL return from readdir() was an error */ + if (errno != 0) { + ERROR("%s: readdir failed", g_plugin_name); + closedir(dir); + return -1; + } + + closedir(dir); + return 0; +} + +static int read_nodes(void) +{ + static const char sys_node[] = "/sys/devices/system/node"; + static const char node_string[] = "node"; + static const char sys_node_hugepages[] = "/sys/devices/system/node/%s/hugepages"; + DIR *dir; + struct dirent *result; + char path[PATH_MAX]; + long lim; + + dir = opendir(sys_node); + if (dir == NULL) { + ERROR("%s: cannot open directory %s", g_plugin_name, sys_node); + return -1; + } + + errno = 0; + if ((lim = pathconf(sys_node, _PC_NAME_MAX)) == -1) { + /* Limit not defined if errno == 0, otherwise error */ + if (errno != 0) { + ERROR("%s: pathconf failed", g_plugin_name); + closedir(dir); + return -1; + } else { + lim = PATH_MAX; + } + } + + while ((result = readdir(dir)) != NULL) { + if (strncmp(result->d_name, node_string, sizeof(node_string)-1)) { + /* not node dir */ + errno = 0; + continue; + } + + ssnprintf(path, (size_t) lim, sys_node_hugepages, result->d_name); + read_syshugepages(path, result->d_name); + errno = 0; + } + + /* Check if NULL return from readdir() was an error */ + if (errno != 0) { + ERROR("%s: readdir failed", g_plugin_name); + closedir(dir); + return -1; + } + + closedir(dir); + return 0; +} + + +static int huge_read(void) +{ + static const char sys_mm_hugepages[] = "/sys/kernel/mm/hugepages"; + + if (g_flag_rpt_mm) { + if (read_syshugepages(sys_mm_hugepages, "mm") != 0) { + return -1; + } + } + if (g_flag_rpt_numa) { + if (read_nodes() != 0) { + return -1; + } + } + + return 0; +} + +void module_register(void) +{ + plugin_register_config(g_plugin_name, huge_config_callback, g_config_keys, + g_config_keys_num); + plugin_register_read(g_plugin_name, huge_read); +} + diff --git a/src/types.db b/src/types.db index cc79af07..1ab1d7c6 100644 --- a/src/types.db +++ b/src/types.db @@ -92,6 +92,7 @@ hash_collisions value:DERIVE:0:U http_request_methods value:DERIVE:0:U http_requests value:DERIVE:0:U http_response_codes value:DERIVE:0:U +hugepages free:GAUGE:0:4294967295, used:GAUGE:0:4294967295 humidity value:GAUGE:0:100 if_collisions value:DERIVE:0:U if_dropped rx:DERIVE:0:U, tx:DERIVE:0:U