2 * collectd - src/hugepages.c
5 * Copyright(c) 2016 Intel Corporation. All rights reserved.
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * Jaroslav Safka <jaroslavx.safka@intel.com>
27 * Kim-Marie Jones <kim-marie.jones@intel.com>
31 #include "common.h" /* auxiliary functions */
32 #include "plugin.h" /* plugin_register_*, plugin_dispatch_values */
34 static const char g_plugin_name[] = "hugepages";
35 static const char g_cfg_rpt_numa[] = "ReportPerNodeHP";
36 static const char g_cfg_rpt_mm[] = "ReportRootHP";
38 static const char *g_config_keys[] = {
39 g_cfg_rpt_numa, g_cfg_rpt_mm,
41 static size_t g_config_keys_num = STATIC_ARRAY_SIZE(g_config_keys);
42 static int g_flag_rpt_numa = 1;
43 static int g_flag_rpt_mm = 1;
45 #define HP_HAVE_NR 0x01
46 #define HP_HAVE_SURPLUS 0x02
47 #define HP_HAVE_FREE 0x04
48 #define HP_HAVE_ALL 0x07
60 static int huge_config_callback(const char *key, const char *val) {
61 DEBUG("%s: HugePages config key='%s', val='%s'", g_plugin_name, key, val);
63 if (strcasecmp(key, g_cfg_rpt_numa) == 0) {
64 g_flag_rpt_numa = IS_TRUE(val);
67 if (strcasecmp(key, g_cfg_rpt_mm) == 0) {
68 g_flag_rpt_mm = IS_TRUE(val);
75 static void submit_hp(const char *plug_inst, const char *type_instance,
76 gauge_t free_value, gauge_t used_value) {
77 value_list_t vl = VALUE_LIST_INIT;
79 { .gauge = free_value },
80 { .gauge = used_value },
84 vl.values_len = STATIC_ARRAY_SIZE (values);
85 sstrncpy(vl.host, hostname_g, sizeof(vl.host));
86 sstrncpy(vl.plugin, g_plugin_name, sizeof(vl.plugin));
87 sstrncpy(vl.plugin_instance, plug_inst, sizeof(vl.plugin_instance));
88 sstrncpy(vl.type, "hugepages", sizeof(vl.type));
90 if (type_instance != NULL) {
91 sstrncpy(vl.type_instance, type_instance, sizeof(vl.type_instance));
94 DEBUG("submit_hp pl_inst:%s, inst_type %s, free=%lf, used=%lf", plug_inst,
95 type_instance, free_value, used_value);
97 plugin_dispatch_values(&vl);
100 static int read_hugepage_entry(const char *path, const char *entry,
102 char path2[PATH_MAX];
103 static const char partial_type_inst[] = "free_used";
104 char type_instance[PATH_MAX];
106 struct entry_info *info = e_info;
109 ssnprintf(path2, sizeof(path2), "%s/%s", path, entry);
111 FILE *fh = fopen(path2, "rt");
113 ERROR("%s: cannot open %s", g_plugin_name, path2);
117 if (fscanf(fh, "%lf", &value) != 1) {
118 ERROR("%s: cannot parse file %s", g_plugin_name, path2);
124 if (strcmp(entry, "nr_hugepages") == 0) {
126 info->flags |= HP_HAVE_NR;
127 } else if (strcmp(entry, "surplus_hugepages") == 0) {
128 info->surplus = value;
129 info->flags |= HP_HAVE_SURPLUS;
130 } else if (strcmp(entry, "free_hugepages") == 0) {
132 info->flags |= HP_HAVE_FREE;
135 if (info->flags != HP_HAVE_ALL) {
139 /* Can now submit "used" and "free" values.
140 * 0x2D is the ASCII "-" character, after which the string
141 * contains "<size>kB"
142 * The string passed as param 3 to submit_hp is of the format:
143 * <type>-<partial_type_inst>-<size>kB
145 assert(strncmp(info->d_name, "hugepages-", strlen("hugepages-")) == 0);
146 strin = info->d_name += strlen("hugepages-");
148 ssnprintf(type_instance, sizeof(type_instance), "%s-%s", partial_type_inst,
150 submit_hp(info->node, type_instance, info->free,
151 (info->nr + info->surplus) - info->free);
153 /* Reset flags so subsequent calls don't submit again. */
158 static int read_syshugepages(const char *path, const char *node) {
159 static const char hugepages_dir[] = "hugepages-";
161 struct dirent *result;
162 char path2[PATH_MAX];
166 ERROR("%s: cannot open directory %s", g_plugin_name, path);
170 /* read "hugepages-XXXXXkB" entries */
171 while ((result = readdir(dir)) != NULL) {
172 if (strncmp(result->d_name, hugepages_dir, sizeof(hugepages_dir) - 1)) {
178 /* /sys/devices/system/node/node?/hugepages/ */
179 ssnprintf(path2, sizeof(path2), "%s/%s", path, result->d_name);
181 walk_directory(path2, read_hugepage_entry,
182 &(struct entry_info){
183 .d_name = result->d_name, .node = node,
189 /* Check if NULL return from readdir() was an error */
191 ERROR("%s: readdir failed", g_plugin_name);
200 static int read_nodes(void) {
201 static const char sys_node[] = "/sys/devices/system/node";
202 static const char node_string[] = "node";
203 static const char sys_node_hugepages[] =
204 "/sys/devices/system/node/%s/hugepages";
206 struct dirent *result;
209 dir = opendir(sys_node);
211 ERROR("%s: cannot open directory %s", g_plugin_name, sys_node);
215 while ((result = readdir(dir)) != NULL) {
216 if (strncmp(result->d_name, node_string, sizeof(node_string) - 1)) {
222 ssnprintf(path, sizeof(path), sys_node_hugepages, result->d_name);
223 read_syshugepages(path, result->d_name);
227 /* Check if NULL return from readdir() was an error */
229 ERROR("%s: readdir failed", g_plugin_name);
238 static int huge_read(void) {
239 static const char sys_mm_hugepages[] = "/sys/kernel/mm/hugepages";
242 if (read_syshugepages(sys_mm_hugepages, "mm") != 0) {
246 if (g_flag_rpt_numa) {
247 if (read_nodes() != 0) {
255 void module_register(void) {
256 plugin_register_config(g_plugin_name, huge_config_callback, g_config_keys,
258 plugin_register_read(g_plugin_name, huge_read);