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";
36 static _Bool g_flag_rpt_numa = 1;
37 static _Bool g_flag_rpt_mm = 1;
39 static _Bool values_pages = 1;
40 static _Bool values_bytes = 0;
41 static _Bool values_percent = 0;
43 #define HP_HAVE_NR 0x01
44 #define HP_HAVE_SURPLUS 0x02
45 #define HP_HAVE_FREE 0x04
46 #define HP_HAVE_ALL 0x07
59 static int hp_config(oconfig_item_t *ci) {
60 for (int i = 0; i < ci->children_num; i++) {
61 oconfig_item_t *child = ci->children + i;
62 if (strcasecmp("ReportPerNodeHP", child->key) == 0)
63 cf_util_get_boolean(child, &g_flag_rpt_numa);
64 else if (strcasecmp("ReportRootHP", child->key) == 0)
65 cf_util_get_boolean(child, &g_flag_rpt_mm);
66 else if (strcasecmp("ValuesPages", child->key) == 0)
67 cf_util_get_boolean(child, &values_pages);
68 else if (strcasecmp("ValuesBytes", child->key) == 0)
69 cf_util_get_boolean(child, &values_bytes);
70 else if (strcasecmp("ValuesPercentage", child->key) == 0)
71 cf_util_get_boolean(child, &values_percent);
73 ERROR("%s: Invalid configuration option: \"%s\".", g_plugin_name,
80 static void submit_hp(const struct entry_info *info) {
81 value_list_t vl = VALUE_LIST_INIT;
83 vl.values = &(value_t) { .gauge = NAN };
86 sstrncpy(vl.host, hostname_g, sizeof(vl.host));
87 sstrncpy(vl.plugin, g_plugin_name, sizeof(vl.plugin));
89 ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%s-%zuKb",
90 info->node, info->page_size_kb);
92 ssnprintf(vl.plugin_instance, sizeof(vl.plugin_instance), "%zuKb",
96 /* ensure all metrics have the same timestamp */
99 gauge_t free = info->free;
100 gauge_t used = (info->nr + info->surplus) - info->free;
103 sstrncpy(vl.type, "vmpage_number", sizeof(vl.type));
104 plugin_dispatch_multivalue(&vl, /* store_percentage = */ 0, DS_TYPE_GAUGE,
105 "free", free, "used", used, NULL);
108 gauge_t page_size = (gauge_t)(1024 * info->page_size_kb);
109 sstrncpy(vl.type, "memory", sizeof(vl.type));
110 plugin_dispatch_multivalue(&vl, /* store_percentage = */ 0, DS_TYPE_GAUGE,
111 "free", free * page_size, "used",
112 used * page_size, NULL);
114 if (values_percent) {
115 sstrncpy(vl.type, "percent", sizeof(vl.type));
116 plugin_dispatch_multivalue(&vl, /* store_percentage = */ 1, DS_TYPE_GAUGE,
117 "free", free, "used", used, NULL);
121 static int read_hugepage_entry(const char *path, const char *entry,
123 char path2[PATH_MAX];
124 char type_instance[PATH_MAX];
125 struct entry_info *info = e_info;
128 ssnprintf(path2, sizeof(path2), "%s/%s", path, entry);
130 FILE *fh = fopen(path2, "rt");
132 ERROR("%s: cannot open %s", g_plugin_name, path2);
136 if (fscanf(fh, "%lf", &value) != 1) {
137 ERROR("%s: cannot parse file %s", g_plugin_name, path2);
143 if (strcmp(entry, "nr_hugepages") == 0) {
145 info->flags |= HP_HAVE_NR;
146 } else if (strcmp(entry, "surplus_hugepages") == 0) {
147 info->surplus = value;
148 info->flags |= HP_HAVE_SURPLUS;
149 } else if (strcmp(entry, "free_hugepages") == 0) {
151 info->flags |= HP_HAVE_FREE;
154 if (info->flags != HP_HAVE_ALL) {
158 ssnprintf(type_instance, sizeof(type_instance), "free_used-%zukB",
162 /* Reset flags so subsequent calls don't submit again. */
167 static int read_syshugepages(const char *path, const char *node) {
168 static const char hugepages_dir[] = "hugepages-";
170 struct dirent *result;
171 char path2[PATH_MAX];
175 ERROR("%s: cannot open directory %s", g_plugin_name, path);
179 /* read "hugepages-XXXXXkB" entries */
180 while ((result = readdir(dir)) != NULL) {
181 if (strncmp(result->d_name, hugepages_dir, sizeof(hugepages_dir) - 1)) {
187 long page_size = strtol(result->d_name + strlen(hugepages_dir),
188 /* endptr = */ NULL, /* base = */ 10);
191 ERROR("%s: failed to determine page size from directory name \"%s\": %s",
192 g_plugin_name, result->d_name,
193 sstrerror(errno, errbuf, sizeof(errbuf)));
197 /* /sys/devices/system/node/node?/hugepages/ */
198 ssnprintf(path2, sizeof(path2), "%s/%s", path, result->d_name);
200 walk_directory(path2, read_hugepage_entry,
201 &(struct entry_info){
202 .d_name = result->d_name,
204 .page_size_kb = (size_t)page_size,
210 /* Check if NULL return from readdir() was an error */
212 ERROR("%s: readdir failed", g_plugin_name);
221 static int read_nodes(void) {
222 static const char sys_node[] = "/sys/devices/system/node";
223 static const char node_string[] = "node";
224 static const char sys_node_hugepages[] =
225 "/sys/devices/system/node/%s/hugepages";
227 struct dirent *result;
230 dir = opendir(sys_node);
232 ERROR("%s: cannot open directory %s", g_plugin_name, sys_node);
236 while ((result = readdir(dir)) != NULL) {
237 if (strncmp(result->d_name, node_string, sizeof(node_string) - 1)) {
243 ssnprintf(path, sizeof(path), sys_node_hugepages, result->d_name);
244 read_syshugepages(path, result->d_name);
248 /* Check if NULL return from readdir() was an error */
250 ERROR("%s: readdir failed", g_plugin_name);
259 static int huge_read(void) {
260 static const char sys_mm_hugepages[] = "/sys/kernel/mm/hugepages";
263 if (read_syshugepages(sys_mm_hugepages, "mm") != 0) {
267 if (g_flag_rpt_numa) {
268 if (read_nodes() != 0) {
276 void module_register(void) {
277 plugin_register_complex_config(g_plugin_name, hp_config);
278 plugin_register_read(g_plugin_name, huge_read);