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 of
8 * this software and associated documentation files (the "Software"), to deal in
9 * the Software without restriction, including without limitation the rights to
10 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
11 * of the Software, and to permit persons to whom the Software is furnished to do
12 * so, subject to the following conditions:
14 * The above copyright notice and this permission notice shall be included in all
15 * 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[] = {
42 static size_t g_config_keys_num = STATIC_ARRAY_SIZE(g_config_keys);
43 static int g_flag_rpt_numa = 1;
44 static int g_flag_rpt_mm = 1;
51 static int huge_config_callback(const char *key, const char *val)
53 INFO("%s: HugePages config key='%s', val='%s'", g_plugin_name, key, val);
55 if (strcasecmp(key, g_cfg_rpt_numa) == 0) {
56 g_flag_rpt_numa = IS_TRUE(val);
59 if (strcasecmp(key, g_cfg_rpt_mm) == 0) {
60 g_flag_rpt_mm = IS_TRUE(val);
67 static void submit_hp(const char *plug_inst, const char *type,
68 const char *type_instance, gauge_t free_value, gauge_t used_value)
71 value_list_t vl = VALUE_LIST_INIT;
73 values[0].gauge = free_value;
74 values[1].gauge = used_value;
78 sstrncpy (vl.host, hostname_g, sizeof (vl.host));
79 sstrncpy (vl.plugin, g_plugin_name, sizeof (vl.plugin));
80 sstrncpy (vl.plugin_instance, plug_inst, sizeof (vl.plugin_instance));
81 sstrncpy (vl.type, type, sizeof (vl.type));
83 if (type_instance != NULL) {
84 sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
87 DEBUG("submit_hp pl_inst:%s, inst_type %s, type %s, free=%lf, used=%lf",
88 plug_inst, type_instance, type, free_value, used_value);
90 plugin_dispatch_values (&vl);
93 static int read_hugepage_entry(const char *path, const char *entry,
97 char *type = "hugepages";
98 char *partial_type_inst = "free_used";
99 char type_instance[PATH_MAX];
101 struct entry_info *hpsize_plinst = (struct entry_info *) e_info;
103 static double used_hp = 0;
104 static double free_hp = 0;
107 ssnprintf(path2, sizeof(path2), "%s/%s", path, entry);
109 FILE *fh = fopen(path2, "rt");
111 ERROR("%s: cannot open %s", g_plugin_name, path2);
115 if (fscanf(fh, "%lf", &value) !=1) {
116 ERROR("%s: cannot parse file %s", g_plugin_name, path2);
121 if (strcmp(entry, "nr_hugepages") == 0) {
124 } else if (strcmp(entry, "surplus_hugepages") == 0) {
127 } else if (strcmp(entry, "free_hugepages") == 0) {
134 /* Can now submit "used" and "free" values.
135 * 0x2D is the ASCII "-" character, after which the string
136 * contains "<size>kB"
137 * The string passed as param 3 to submit_hp is of the format:
138 * <type>-<partial_type_inst>-<size>kB
140 strin = strchr(hpsize_plinst->d_name, 0x2D);
142 ssnprintf(type_instance, sizeof(type_instance), "%s%s", partial_type_inst, strin);
144 ssnprintf(type_instance, sizeof(type_instance), "%s%s", partial_type_inst,
145 hpsize_plinst->d_name);
147 submit_hp(hpsize_plinst->node, type, type_instance, free_hp, used_hp);
149 /* Reset for next time */
159 static int read_syshugepages(const char* path, const char* node)
161 const char hugepages_dir[] = "hugepages";
163 struct dirent *result = NULL;
164 char path2[PATH_MAX];
165 struct entry_info e_info;
169 ERROR("%s: cannot open directory %s", g_plugin_name, path);
173 if (pathconf(path, _PC_NAME_MAX) == -1) {
174 /* Limit not defined, or error */
175 ERROR("%s: pathconf failed", g_plugin_name);
180 /* read "hugepages-XXXXXkB" entries */
181 while ((result = readdir(dir)) != NULL) {
182 if (strncmp(result->d_name, hugepages_dir, sizeof(hugepages_dir)-1)) {
187 /* /sys/devices/system/node/node?/hugepages/ */
188 ssnprintf(path2, sizeof(path2), "%s/%s", path, result->d_name);
190 e_info.d_name = result->d_name;
191 e_info.node = (char *) node;
192 walk_directory(path2, read_hugepage_entry, (void *) &e_info, 0);
200 static int read_nodes(void)
202 const char sys_node[] = "/sys/devices/system/node";
203 const char node_string[] = "node";
204 const char sys_node_hugepages[] = "/sys/devices/system/node/%s/hugepages";
206 struct dirent *result = NULL;
209 dir = opendir(sys_node);
211 ERROR("%s: cannot open directory %s", g_plugin_name, sys_node);
215 if (pathconf(sys_node, _PC_NAME_MAX) == -1) {
216 /* Limit not defined, or error */
217 ERROR("%s: pathconf failed", g_plugin_name);
222 while ((result = readdir(dir)) != NULL) {
223 if (strncmp(result->d_name, node_string, sizeof(node_string)-1)) {
228 ssnprintf(path, sizeof(path), sys_node_hugepages, result->d_name);
229 read_syshugepages(path, result->d_name);
238 static int huge_read(void)
240 const char sys_mm_hugepages[] = "/sys/kernel/mm/hugepages";
243 read_syshugepages(sys_mm_hugepages, "mm");
245 if (g_flag_rpt_numa) {
252 void module_register(void)
254 plugin_register_config(g_plugin_name, huge_config_callback, g_config_keys,
256 plugin_register_read(g_plugin_name, huge_read);