db18de05531ae8a7e42fb7de3322ac3f5fd9e350
1 /*-
2 * collectd - src/hugepages.c
3 * MIT License
4 *
5 * Copyright(c) 2016 Intel Corporation. All rights reserved.
6 *
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:
13 *
14 * The above copyright notice and this permission notice shall be included in all
15 * copies or substantial portions of the Software.
16 *
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
23 * SOFTWARE.
24 *
25 * Authors:
26 * Jaroslav Safka <jaroslavx.safka@intel.com>
27 */
29 #include "collectd.h"
30 #include "common.h" /* auxiliary functions */
31 #include "plugin.h" /* plugin_register_*, plugin_dispatch_values */
33 #include <stdio.h>
34 #include <string.h>
35 #include <dirent.h>
37 static int huge_read (void);
38 static int huge_config_callback (const char *key, const char *val);
40 static const char PLUGIN_NAME[] = "hugepages";
41 static const char SYS_NODE[] = "/sys/devices/system/node";
42 static const char NODE[] = "node";
43 static const char HUGEPAGES_DIR[] = "hugepages";
44 static const char SYS_NODE_HUGEPAGES[] = "/sys/devices/system/node/%s/hugepages";
45 static const char SYS_MM_HUGEPAGES[] = "/sys/kernel/mm/hugepages";
46 static const char CONFIG_NAME[] = "hugepages";
47 static const char CFG_ENA_NUMA[] = "EnableNuma";
48 static const char CFG_ENA_MM[] = "EnableMM";
50 static const char *CONFIG_KEYS[] = {
51 CFG_ENA_NUMA,
52 CFG_ENA_MM,
53 };
54 static const size_t CONFIG_KEYS_NUM = sizeof(CONFIG_KEYS)/sizeof(*CONFIG_NAME);
55 static int g_config_ena_numa = 1;
56 static int g_config_ena_mm = 1;
58 static int huge_config_callback (const char *key, const char *val)
59 {
60 INFO("HugePages config key='%s', val='%s'", key, val);
62 if (0 == strcasecmp(key, CFG_ENA_NUMA)) {
63 g_config_ena_numa = IS_TRUE(val);
64 return 0;
65 }
66 if (0 == strcasecmp(key, CFG_ENA_MM)) {
67 g_config_ena_mm = IS_TRUE(val);
68 return 0;
69 }
71 return -1;
72 }
74 static void submit_one (const char *plug_inst, const char *type,
75 const char *type_instance, derive_t value)
76 {
77 value_t values[1];
78 value_list_t vl = VALUE_LIST_INIT;
80 values[0].derive = value;
82 vl.values = values;
83 vl.values_len = 1;
84 sstrncpy (vl.host, hostname_g, sizeof (vl.host));
85 sstrncpy (vl.plugin, PLUGIN_NAME, sizeof (vl.plugin));
86 sstrncpy (vl.plugin_instance, plug_inst, sizeof (vl.plugin_instance));
87 sstrncpy (vl.type, type, sizeof (vl.type));
89 if (type_instance != NULL) {
90 sstrncpy (vl.type_instance, type_instance, sizeof (vl.type_instance));
91 }
93 DEBUG("submit_one pl_inst:%s, inst_type %s, type %s, val=%lu",
94 plug_inst, type_instance, type, value);
96 plugin_dispatch_values (&vl);
97 }
99 static int read_hugepage_entry(const char *path, const char* entry,
100 const char* plinst, const char* hpsize)
101 {
102 char path2[512];
103 long value = 0;
104 snprintf(path2, sizeof(path2), "%s/%s", path, entry);
106 FILE *fh = fopen(path2, "rt");
107 if (NULL == fh) {
108 ERROR("Cannot open %s", path2);
109 return -1;
110 }
112 if (fscanf(fh, "%ld", &value) !=1) {
113 ERROR("Cannot parse file %s", path2);
114 fclose(fh);
115 return -1;
116 }
118 submit_one (plinst, entry, hpsize, value);
120 fclose(fh);
121 return 0;
122 }
124 static int read_syshugepage_dir(const char* path, const char* dirhpsize,
125 const char* node)
126 {
127 DIR *dir = NULL;
128 struct dirent *entry = NULL;
129 struct dirent *result = NULL;
130 size_t name_max = 0;
131 size_t len = 0;
133 dir = opendir(path);
134 if (NULL == dir) {
135 ERROR("Cannot open directory %s", path);
136 return -1;
137 }
139 name_max = pathconf(path, _PC_NAME_MAX);
140 if (name_max == -1) { /* Limit not defined, or error */
141 name_max = 255; /* Take a guess */
142 }
144 len = offsetof(struct dirent, d_name) + name_max + 1;
145 entry = malloc(len);
146 if (entry == NULL) {
147 ERROR("Malloc returned NULL");
148 return -1;
149 }
151 while (0 == readdir_r(dir, entry, &result)) {
152 if (NULL == result) {
153 /* end of dir */
154 break;
155 }
156 if (result->d_name[0] == '.') {
157 /* not interesting "." and ".." */
158 continue;
159 }
161 read_hugepage_entry(path, result->d_name, node, dirhpsize);
162 }
164 free(entry);
165 closedir(dir);
168 return 0;
169 }
171 static int read_syshugepages(const char* path, const char* node)
172 {
173 DIR *dir = NULL;
174 struct dirent *entry = NULL;
175 struct dirent *result = NULL;
176 size_t name_max = 0;
177 size_t len = 0;
178 char path2[255];
180 dir = opendir(path);
181 if (NULL == dir) {
182 ERROR("Cannot open directory %s", path);
183 return -1;
184 }
186 name_max = pathconf(path, _PC_NAME_MAX);
187 if (name_max == -1) { /* Limit not defined, or error */
188 name_max = 255; /* Take a guess */
189 }
190 len = offsetof(struct dirent, d_name) + name_max + 1;
191 entry = malloc(len);
192 if (entry == NULL) {
193 ERROR("Malloc returned NULL");
194 return -1;
195 }
197 while (0 == readdir_r(dir, entry, &result)) {
198 /* read "hugepages-XXXXXkB" entries */
199 if (NULL == result) {
200 /* end of dir */
201 break;
202 }
204 if (strncmp(result->d_name, HUGEPAGES_DIR, sizeof(HUGEPAGES_DIR)-1)) {
205 /* not node dir */
206 continue;
207 }
209 /* /sys/devices/system/node/node?/hugepages/ */
210 snprintf(path2, sizeof(path2), "%s/%s", path, result->d_name);
211 read_syshugepage_dir(path2, result->d_name, node);
212 }
214 free(entry);
215 closedir(dir);
217 return 0;
218 }
220 static int read_nodes(void)
221 {
222 DIR *dir = NULL;
223 struct dirent *entry = NULL;
224 struct dirent *result = NULL;
225 size_t name_max = 0;
226 size_t len = 0;
227 char path[255];
229 dir = opendir(SYS_NODE);
230 if (NULL == dir) {
231 ERROR("Cannot open directory %s", SYS_NODE);
232 return -1;
233 }
235 name_max = pathconf(SYS_NODE, _PC_NAME_MAX);
236 if (name_max == -1) { /* Limit not defined, or error */
237 name_max = 255; /* Take a guess */
238 }
239 len = offsetof(struct dirent, d_name) + name_max + 1;
240 entry = malloc(len);
241 if (entry == NULL) {
242 ERROR("Malloc returned NULL");
243 return -1;
244 }
246 while (0 == readdir_r(dir, entry, &result)) {
247 if (NULL == result) {
248 /* end of dir */
249 break;
250 }
252 if (strncmp(result->d_name, NODE, sizeof(NODE)-1)) {
253 /* not node dir */
254 continue;
255 }
257 snprintf(path, sizeof(path), SYS_NODE_HUGEPAGES, result->d_name);
258 read_syshugepages(path, result->d_name);
259 }
261 free(entry);
262 closedir(dir);
264 return 0;
265 }
268 static int huge_read (void)
269 {
270 if (g_config_ena_mm) {
271 read_syshugepages(SYS_MM_HUGEPAGES, "mm");
272 }
273 if (g_config_ena_numa) {
274 read_nodes();
275 }
277 return 0;
278 }
280 void module_register (void)
281 {
282 plugin_register_config(CONFIG_NAME, huge_config_callback, CONFIG_KEYS,
283 CONFIG_KEYS_NUM);
284 plugin_register_read (PLUGIN_NAME, huge_read);
285 }