]> git.ipfire.org Git - thirdparty/collectd.git/blame - src/memory.c
memory plugin: Remove "slab" and "available" memory.
[thirdparty/collectd.git] / src / memory.c
CommitLineData
7fa270a1
FF
1/**
2 * collectd - src/memory.c
71b4a17a 3 * Copyright (C) 2005-2020 Florian octo Forster
eeb8f7f4 4 * Copyright (C) 2009 Simon Kuhnle
f1b812b3 5 * Copyright (C) 2009 Manuel Sanmartin
7fa270a1
FF
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
293819d0 9 * Free Software Foundation; only version 2 of the License is applicable.
7fa270a1
FF
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 *
20 * Authors:
633c3966 21 * Florian octo Forster <octo at collectd.org>
eeb8f7f4 22 * Simon Kuhnle <simon at blarzwurst.de>
f1b812b3 23 * Manuel Sanmartin
7fa270a1
FF
24 **/
25
73681054 26#include "collectd.h"
a5377cf9 27
73681054 28#include "plugin.h"
6378ec28 29#include "utils/common/common.h"
7fa270a1 30
f22b9ecc
ZS
31#if (defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTLBYNAME)) || \
32 defined(__OpenBSD__)
a937f260 33/* Implies BSD variant */
936c450a 34#include <sys/sysctl.h>
b8248eb1 35#endif
8fce2979 36#ifdef HAVE_SYS_VMMETER_H
936c450a 37#include <sys/vmmeter.h>
8fce2979 38#endif
7fa270a1 39
4d25c0e0 40#ifdef HAVE_MACH_KERN_RETURN_H
936c450a 41#include <mach/kern_return.h>
4d25c0e0
FF
42#endif
43#ifdef HAVE_MACH_MACH_INIT_H
936c450a 44#include <mach/mach_init.h>
4d25c0e0 45#endif
984e46be 46#ifdef HAVE_MACH_MACH_HOST_H
936c450a 47#include <mach/mach_host.h>
984e46be 48#endif
4d25c0e0 49#ifdef HAVE_MACH_HOST_PRIV_H
936c450a 50#include <mach/host_priv.h>
4d25c0e0 51#endif
f5adb596 52#ifdef HAVE_MACH_VM_STATISTICS_H
936c450a 53#include <mach/vm_statistics.h>
984e46be 54#endif
4d25c0e0 55
f05e9721 56#if HAVE_STATGRAB_H
936c450a 57#include <statgrab.h>
f05e9721
FF
58#endif
59
f1b812b3 60#if HAVE_PERFSTAT
936c450a
FF
61#include <libperfstat.h>
62#include <sys/protosw.h>
f1b812b3
MS
63#endif /* HAVE_PERFSTAT */
64
2a056a37
FF
65static char const *const label_state = "system.memory.state";
66
71b4a17a 67typedef enum {
8ec9a545
FF
68 STATE_USED,
69 STATE_FREE,
70 STATE_BUFFERS,
71 STATE_CACHED,
8ec9a545
FF
72 STATE_WIRED,
73 STATE_ACTIVE,
74 STATE_INACTIVE,
75 STATE_KERNEL,
76 STATE_LOCKED,
77 STATE_ARC,
78 STATE_UNUSED,
8ec9a545
FF
79 STATE_USER_WIRE,
80 STATE_LAUNDRY,
81 STATE_MAX, /* #states */
71b4a17a
FF
82} memory_type_t;
83
8ec9a545 84static char const *memory_type_names[STATE_MAX] = {
c575d3e8
FF
85 "used", "free", "buffers", "cached", "wired",
86 "active", "inactive", "kernel", "locked", "arc",
87 "unusable", "user_wire", "laundry",
71b4a17a
FF
88};
89
4d25c0e0 90/* vm_statistics_data_t */
e2df2097 91#if HAVE_HOST_STATISTICS
4d25c0e0
FF
92static mach_port_t port_host;
93static vm_size_t pagesize;
e2df2097 94/* #endif HAVE_HOST_STATISTICS */
4d25c0e0 95
74da5795 96#elif HAVE_SYSCTLBYNAME
5eebeafe
EF
97#if HAVE_SYSCTL && defined(KERNEL_NETBSD)
98static int pagesize;
99#include <unistd.h> /* getpagesize() */
100#else
b8248eb1 101/* no global variables */
5eebeafe 102#endif
74da5795 103/* #endif HAVE_SYSCTLBYNAME */
b8248eb1
FF
104
105#elif KERNEL_LINUX
4d25c0e0
FF
106/* no global variables */
107/* #endif KERNEL_LINUX */
108
b8248eb1 109#elif HAVE_LIBKSTAT
7fa270a1
FF
110static int pagesize;
111static kstat_t *ksp;
d13ba64e 112static kstat_t *ksz;
e4b274ed
FF
113/* #endif HAVE_LIBKSTAT */
114
4a2ec3e0 115#elif HAVE_SYSCTL && __OpenBSD__
f22b9ecc 116/* OpenBSD variant does not have sysctlbyname */
38f27d54 117static int pagesize;
4a2ec3e0 118/* #endif HAVE_SYSCTL && __OpenBSD__ */
38f27d54 119
f05e9721
FF
120#elif HAVE_LIBSTATGRAB
121/* no global variables */
122/* endif HAVE_LIBSTATGRAB */
f1b812b3
MS
123#elif HAVE_PERFSTAT
124static int pagesize;
f1b812b3 125/* endif HAVE_PERFSTAT */
e4b274ed 126#else
936c450a 127#error "No applicable input method."
e4b274ed 128#endif
7fa270a1 129
c920cda8 130#if KERNEL_NETBSD
30318d13 131#include <uvm/uvm_extern.h>
c920cda8
EF
132#endif
133
67285dfc 134static bool report_usage = true;
ede88c1b 135static bool report_utilization = true;
9f1a78d5 136static bool report_limit;
1aa8032d 137
936c450a 138static int memory_config(oconfig_item_t *ci) /* {{{ */
1aa8032d 139{
936c450a
FF
140 for (int i = 0; i < ci->children_num; i++) {
141 oconfig_item_t *child = ci->children + i;
67285dfc
FF
142 if (strcasecmp("ReportUsage", child->key) == 0 ||
143 strcasecmp("ValuesAbsolute", child->key) == 0)
144 cf_util_get_boolean(child, &report_usage);
5877b8d0
FF
145 else if (strcasecmp("ReportUtilization", child->key) == 0 ||
146 strcasecmp("ValuesPercentage", child->key) == 0)
147 cf_util_get_boolean(child, &report_utilization);
9f1a78d5
FF
148 else if (strcasecmp("ReportLimit", child->key) == 0)
149 cf_util_get_boolean(child, &report_limit);
936c450a 150 else
71b4a17a 151 ERROR("memory plugin: Invalid configuration option: \"%s\".", child->key);
936c450a
FF
152 }
153
307c875e 154 return 0;
1aa8032d
JK
155} /* }}} int memory_config */
156
8ec9a545 157static int memory_dispatch(gauge_t values[STATE_MAX]) {
67285dfc 158 metric_family_t fam_usage = {
eb249dc2 159 .name = "system.memory.usage",
4616f834
FF
160 .help = "Reports memory in use by state",
161 .unit = "By",
71b4a17a
FF
162 .type = METRIC_TYPE_GAUGE,
163 };
164 gauge_t total = 0;
165
8ec9a545 166 for (size_t i = 0; i < STATE_MAX; i++) {
71b4a17a
FF
167 if (isnan(values[i])) {
168 continue;
169 }
170
171 total += values[i];
172
67285dfc
FF
173 if (report_usage) {
174 metric_family_append(&fam_usage, label_state, memory_type_names[i],
2a056a37 175 (value_t){.gauge = values[i]}, NULL);
71b4a17a
FF
176 }
177 }
178
179 int ret = 0;
67285dfc
FF
180 if (report_usage) {
181 int status = plugin_dispatch_metric_family(&fam_usage);
71b4a17a
FF
182 if (status != 0) {
183 ERROR("memory plugin: plugin_dispatch_metric_family failed: %s",
184 STRERROR(status));
185 }
186 ret = status;
187 }
67285dfc 188 metric_family_metric_reset(&fam_usage);
71b4a17a 189
71b4a17a
FF
190 if (total == 0) {
191 return EINVAL;
192 }
193
9f1a78d5
FF
194 if (report_limit) {
195 metric_family_t fam_limit = {
196 .name = "system.memory.limit",
197 .help = "Total memory available in the system.",
198 .unit = "By",
199 .type = METRIC_TYPE_COUNTER, // [sic] should be UpDownCounter
200 };
201 metric_t m = {
202 .value = (value_t){.derive = (derive_t)total},
203 };
204 metric_family_metric_append(&fam_limit, m);
205
206 int status = plugin_dispatch_metric_family(&fam_limit);
207 if (status != 0) {
208 ERROR("memory plugin: plugin_dispatch_metric_family failed: %s",
209 STRERROR(status));
210 }
211 ret = ret ? ret : status;
212 }
213
214 if (!report_utilization) {
215 return ret;
216 }
217
81425990 218 metric_family_t fam_util = {
eb249dc2 219 .name = "system.memory.utilization",
4616f834
FF
220 .help = "Reports memory in use by state",
221 .unit = "1",
71b4a17a
FF
222 .type = METRIC_TYPE_GAUGE,
223 };
8ec9a545 224 for (size_t i = 0; i < STATE_MAX; i++) {
71b4a17a
FF
225 if (isnan(values[i])) {
226 continue;
227 }
228
81425990
FF
229 metric_family_append(&fam_util, label_state, memory_type_names[i],
230 (value_t){.gauge = values[i] / total}, NULL);
71b4a17a
FF
231 }
232
81425990 233 int status = plugin_dispatch_metric_family(&fam_util);
71b4a17a
FF
234 if (status != 0) {
235 ERROR("memory plugin: plugin_dispatch_metric_family failed: %s",
236 STRERROR(status));
237 ret = ret ? ret : status;
238 }
81425990 239 metric_family_metric_reset(&fam_util);
71b4a17a
FF
240
241 return ret;
242}
243
936c450a 244static int memory_init(void) {
e2df2097 245#if HAVE_HOST_STATISTICS
936c450a
FF
246 port_host = mach_host_self();
247 host_page_size(port_host, &pagesize);
ec9234cd 248 /* #endif HAVE_HOST_STATISTICS */
4d25c0e0 249
74da5795 250#elif HAVE_SYSCTLBYNAME
5eebeafe
EF
251#if HAVE_SYSCTL && defined(KERNEL_NETBSD)
252 pagesize = getpagesize();
253#else
254/* no init stuff */
255#endif /* HAVE_SYSCTL && defined(KERNEL_NETBSD) */
60c914f1 256 /* #endif HAVE_SYSCTLBYNAME */
b8248eb1 257
4d25c0e0 258#elif defined(KERNEL_LINUX)
60c914f1
FF
259 /* no init stuff */
260 /* #endif KERNEL_LINUX */
4d25c0e0
FF
261
262#elif defined(HAVE_LIBKSTAT)
936c450a
FF
263 /* getpagesize(3C) tells me this does not fail.. */
264 pagesize = getpagesize();
265 if (get_kstat(&ksp, "unix", 0, "system_pages") != 0) {
266 ksp = NULL;
307c875e 267 return -1;
936c450a
FF
268 }
269 if (get_kstat(&ksz, "zfs", 0, "arcstats") != 0) {
270 ksz = NULL;
307c875e 271 return -1;
936c450a 272 }
d13ba64e 273
60c914f1 274 /* #endif HAVE_LIBKSTAT */
38f27d54 275
4a2ec3e0 276#elif HAVE_SYSCTL && __OpenBSD__
f22b9ecc 277 /* OpenBSD variant does not have sysctlbyname */
936c450a
FF
278 pagesize = getpagesize();
279 if (pagesize <= 0) {
280 ERROR("memory plugin: Invalid pagesize: %i", pagesize);
307c875e 281 return -1;
936c450a 282 }
60c914f1 283 /* #endif HAVE_SYSCTL && __OpenBSD__ */
38f27d54
FF
284
285#elif HAVE_LIBSTATGRAB
60c914f1
FF
286 /* no init stuff */
287 /* #endif HAVE_LIBSTATGRAB */
7fa270a1 288
f1b812b3 289#elif HAVE_PERFSTAT
936c450a 290 pagesize = getpagesize();
f1b812b3 291#endif /* HAVE_PERFSTAT */
307c875e 292 return 0;
293819d0 293} /* int memory_init */
7fa270a1 294
8ec9a545 295static int memory_read_internal(gauge_t values[STATE_MAX]) {
e2df2097 296#if HAVE_HOST_STATISTICS
71b4a17a
FF
297 if (!port_host || !pagesize) {
298 return EINVAL;
299 }
936c450a 300
71b4a17a 301 vm_statistics_data_t vm_data = {0};
60c914f1
FF
302 mach_msg_type_number_t vm_data_len = sizeof(vm_data) / sizeof(natural_t);
303 kern_return_t status = host_statistics(port_host, HOST_VM_INFO,
304 (host_info_t)&vm_data, &vm_data_len);
305 if (status != KERN_SUCCESS) {
306 ERROR("memory-plugin: host_statistics failed and returned the value %d",
936c450a 307 (int)status);
71b4a17a 308 return (int)status;
936c450a
FF
309 }
310
311 /*
312 * From <http://docs.info.apple.com/article.html?artnum=107918>:
313 *
314 * Wired memory
315 * This information can't be cached to disk, so it must stay in RAM.
316 * The amount depends on what applications you are using.
317 *
318 * Active memory
319 * This information is currently in RAM and actively being used.
320 *
321 * Inactive memory
322 * This information is no longer being used and has been cached to
323 * disk, but it will remain in RAM until another application needs
324 * the space. Leaving this information in RAM is to your advantage if
325 * you (or a client of your computer) come back to it later.
326 *
327 * Free memory
328 * This memory is not being used.
329 */
330
8ec9a545
FF
331 values[STATE_WIRED] = (gauge_t)(vm_data.wire_count * pagesize);
332 values[STATE_ACTIVE] = (gauge_t)(vm_data.active_count * pagesize);
333 values[STATE_INACTIVE] = (gauge_t)(vm_data.inactive_count * pagesize);
334 values[STATE_FREE] = (gauge_t)(vm_data.free_count * pagesize);
ec9234cd 335 /* #endif HAVE_HOST_STATISTICS */
4d25c0e0 336
74da5795 337#elif HAVE_SYSCTLBYNAME
c920cda8
EF
338
339#if HAVE_SYSCTL && defined(KERNEL_NETBSD)
71b4a17a
FF
340 if (pagesize == 0) {
341 return EINVAL;
342 }
343
c920cda8 344 int mib[] = {CTL_VM, VM_UVMEXP2};
71b4a17a
FF
345 struct uvmexp_sysctl uvmexp = {0};
346 size_t size = sizeof(uvmexp);
347 if (sysctl(mib, STATIC_ARRAY_SIZE(mib), &uvmexp, &size, NULL, 0) < 0) {
348 WARNING("memory plugin: sysctl failed: %s", STRERRNO);
349 return errno;
c920cda8
EF
350 }
351
8ec9a545
FF
352 values[STATE_WIRED] = (gauge_t)(uvmexp.wired * pagesize);
353 values[STATE_ACTIVE] = (gauge_t)(uvmexp.active * pagesize);
354 values[STATE_INACTIVE] = (gauge_t)(uvmexp.inactive * pagesize);
355 values[STATE_FREE] = (gauge_t)(uvmexp.free * pagesize);
71b4a17a
FF
356
357 int64_t accounted =
358 uvmexp.wired + uvmexp.active + uvmexp.inactive + uvmexp.free;
359 if (uvmexp.npages > accounted) {
8ec9a545 360 values[STATE_KERNEL] = (gauge_t)((uvmexp.npages - accounted) * pagesize);
71b4a17a 361 }
30318d13 362 /* #endif HAVE_SYSCTL && defined(KERNEL_NETBSD) */
c920cda8 363
71b4a17a 364#else /* Other HAVE_SYSCTLBYNAME providers */
936c450a
FF
365 /*
366 * vm.stats.vm.v_page_size: 4096
367 * vm.stats.vm.v_page_count: 246178
368 * vm.stats.vm.v_free_count: 28760
369 * vm.stats.vm.v_wire_count: 37526
370 * vm.stats.vm.v_active_count: 55239
371 * vm.stats.vm.v_inactive_count: 113730
372 * vm.stats.vm.v_cache_count: 10809
8dc63496
FC
373 * vm.stats.vm.v_user_wire_count: 0
374 * vm.stats.vm.v_laundry_count: 40394
936c450a 375 */
60c914f1
FF
376 struct {
377 char const *sysctl_key;
71b4a17a 378 memory_type_t type;
60c914f1 379 } metrics[] = {
71b4a17a 380 {"vm.stats.vm.v_page_size"},
8ec9a545
FF
381 {"vm.stats.vm.v_free_count", STATE_FREE},
382 {"vm.stats.vm.v_wire_count", STATE_WIRED},
383 {"vm.stats.vm.v_active_count", STATE_ACTIVE},
384 {"vm.stats.vm.v_inactive_count", STATE_INACTIVE},
385 {"vm.stats.vm.v_cache_count", STATE_CACHED},
386 {"vm.stats.vm.v_user_wire_count", STATE_USER_WIRE},
387 {"vm.stats.vm.v_laundry_count", STATE_LAUNDRY},
60c914f1
FF
388 };
389
71b4a17a 390 gauge_t pagesize = 0;
60c914f1 391 for (size_t i = 0; i < STATIC_ARRAY_SIZE(metrics); i++) {
71b4a17a 392 long value = 0;
936c450a
FF
393 size_t value_len = sizeof(value);
394
60c914f1
FF
395 int status = sysctlbyname(metrics[i].sysctl_key, (void *)&value, &value_len,
396 NULL, 0);
397 if (status != 0) {
398 WARNING("sysctlbyname(\"%s\") failed: %s", metrics[i].sysctl_key,
399 STRERROR(status));
400 continue;
936c450a 401 }
936c450a 402
60c914f1 403 if (i == 0) {
71b4a17a 404 pagesize = (gauge_t)value;
60c914f1
FF
405 continue;
406 }
936c450a 407
71b4a17a 408 values[metrics[i].type] = ((gauge_t)value) * pagesize;
60c914f1 409 } /* for (sysctl_keys) */
c920cda8 410#endif /* HAVE_SYSCTL && KERNEL_NETBSD */
ec9234cd 411 /* #endif HAVE_SYSCTLBYNAME */
b8248eb1 412
f05e9721 413#elif KERNEL_LINUX
60c914f1
FF
414 FILE *fh = fopen("/proc/meminfo", "r");
415 if (fh == NULL) {
416 int status = errno;
417 ERROR("memory plugin: fopen(\"/proc/meminfo\") failed: %s", STRERRNO);
418 return status;
419 }
936c450a 420
71b4a17a 421 gauge_t mem_total = 0;
60c914f1 422 gauge_t mem_not_used = 0;
936c450a 423
60c914f1 424 char buffer[256];
936c450a 425 while (fgets(buffer, sizeof(buffer), fh) != NULL) {
71b4a17a 426 char *fields[4] = {NULL};
60c914f1
FF
427 int fields_num = strsplit(buffer, fields, STATIC_ARRAY_SIZE(fields));
428 if ((fields_num != 3) || (strcmp("kB", fields[2]) != 0)) {
429 continue;
430 }
431
71b4a17a
FF
432 gauge_t v = 1024.0 * atof(fields[1]);
433 if (!isfinite(v)) {
434 continue;
435 }
60c914f1
FF
436
437 if (strcmp(fields[0], "MemTotal:") == 0) {
71b4a17a 438 mem_total = v;
60c914f1 439 } else if (strcmp(fields[0], "MemFree:") == 0) {
8ec9a545 440 values[STATE_FREE] = v;
71b4a17a 441 mem_not_used += v;
60c914f1 442 } else if (strcmp(fields[0], "Buffers:") == 0) {
8ec9a545 443 values[STATE_BUFFERS] = v;
71b4a17a 444 mem_not_used += v;
60c914f1 445 } else if (strcmp(fields[0], "Cached:") == 0) {
8ec9a545 446 values[STATE_CACHED] = v;
71b4a17a 447 mem_not_used += v;
60c914f1 448 }
936c450a
FF
449 }
450
451 if (fclose(fh)) {
60c914f1 452 WARNING("memory plugin: fclose failed: %s", STRERRNO);
936c450a
FF
453 }
454
71b4a17a 455 if (isnan(mem_total) || (mem_total == 0) || (mem_total < mem_not_used)) {
60c914f1
FF
456 return EINVAL;
457 }
936c450a 458
71b4a17a
FF
459 /* "used" is not explicitly reported. It is calculated as everything that is
460 * not "not used", e.g. cached, buffers, ... */
8ec9a545 461 values[STATE_USED] = mem_total - mem_not_used;
60c914f1 462 /* #endif KERNEL_LINUX */
7fa270a1 463
f05e9721 464#elif HAVE_LIBKSTAT
936c450a
FF
465 /* Most of the additions here were taken as-is from the k9toolkit from
466 * Brendan Gregg and are subject to change I guess */
71b4a17a
FF
467 if ((ksp == NULL) || (ksz == NULL)) {
468 return EINVAL;
469 }
936c450a 470
71b4a17a
FF
471 long long mem_used = get_kstat_value(ksp, "pagestotal");
472 long long mem_free = get_kstat_value(ksp, "pagesfree");
473 long long mem_lock = get_kstat_value(ksp, "pageslocked");
474 long long mem_kern = 0;
475 long long mem_unus = 0;
476 long long arcsize = get_kstat_value(ksz, "size");
936c450a 477
71b4a17a
FF
478 long long pp_kernel = get_kstat_value(ksp, "pp_kernel");
479 long long physmem = get_kstat_value(ksp, "physmem");
480 long long availrmem = get_kstat_value(ksp, "availrmem");
936c450a
FF
481
482 if ((mem_used < 0LL) || (mem_free < 0LL) || (mem_lock < 0LL)) {
71b4a17a 483 ERROR("memory plugin: one of used, free or locked is negative.");
307c875e 484 return -1;
936c450a
FF
485 }
486
487 mem_unus = physmem - mem_used;
488
489 if (mem_used < (mem_free + mem_lock)) {
490 /* source: http://wesunsolve.net/bugid/id/4909199
491 * this seems to happen when swap space is small, e.g. 2G on a 32G system
492 * we will make some assumptions here
493 * educated solaris internals help welcome here */
494 DEBUG("memory plugin: pages total is smaller than \"free\" "
495 "+ \"locked\". This is probably due to small "
496 "swap space");
497 mem_free = availrmem;
498 mem_used = 0;
499 } else {
500 mem_used -= mem_free + mem_lock;
501 }
502
503 /* mem_kern is accounted for in mem_lock */
504 if (pp_kernel < mem_lock) {
505 mem_kern = pp_kernel;
506 mem_lock -= pp_kernel;
507 } else {
508 mem_kern = mem_lock;
509 mem_lock = 0;
510 }
511
8ec9a545
FF
512 values[STATE_USED] = (gauge_t)(mem_used * pagesize);
513 values[STATE_FREE] = (gauge_t)(mem_free * pagesize);
514 values[STATE_LOCKED] = (gauge_t)(mem_lock * pagesize);
515 values[STATE_KERNEL] = (gauge_t)((mem_kern * pagesize) - arcsize);
516 values[STATE_UNUSED] = (gauge_t)(mem_unus * pagesize);
517 values[STATE_ARC] = (gauge_t)arcsize;
ec9234cd 518 /* #endif HAVE_LIBKSTAT */
7fa270a1 519
4a2ec3e0 520#elif HAVE_SYSCTL && __OpenBSD__
f22b9ecc 521 /* OpenBSD variant does not have HAVE_SYSCTLBYNAME */
71b4a17a
FF
522 if (pagesize == 0) {
523 return EINVAL;
524 }
525
936c450a
FF
526 int mib[] = {CTL_VM, VM_METER};
527 struct vmtotal vmtotal = {0};
71b4a17a
FF
528 size_t size = sizeof(vmtotal);
529 if (sysctl(mib, STATIC_ARRAY_SIZE(mib), &vmtotal, &size, NULL, 0) < 0) {
530 ERROR("memory plugin: sysctl failed: %s", STRERRNO);
531 return errno;
936c450a
FF
532 }
533
8ec9a545
FF
534 values[STATE_ACTIVE] = (gauge_t)(vmtotal.t_arm * pagesize);
535 values[STATE_INACTIVE] = (gauge_t)((vmtotal.t_rm - vmtotal.t_arm) * pagesize);
536 values[STATE_FREE] = (gauge_t)(vmtotal.t_free * pagesize);
4a2ec3e0 537 /* #endif HAVE_SYSCTL && __OpenBSD__ */
38f27d54 538
f05e9721 539#elif HAVE_LIBSTATGRAB
71b4a17a
FF
540 sg_mem_stats *ios = sg_get_mem_stats();
541 if (ios == NULL) {
307c875e 542 return -1;
71b4a17a 543 }
c791ba09 544
8ec9a545
FF
545 values[STATE_USED] = (gauge_t)ios->used;
546 values[STATE_CACHED] = (gauge_t)ios->cache;
547 values[STATE_FREE] = (gauge_t)ios->free;
ec9234cd 548 /* #endif HAVE_LIBSTATGRAB */
f1b812b3
MS
549
550#elif HAVE_PERFSTAT
936c450a 551 perfstat_memory_total_t pmemory = {0};
936c450a 552 if (perfstat_memory_total(NULL, &pmemory, sizeof(pmemory), 1) < 0) {
71b4a17a
FF
553 ERROR("memory plugin: perfstat_memory_total failed: %s", STRERRNO);
554 return errno;
936c450a
FF
555 }
556
557 /* Unfortunately, the AIX documentation is not very clear on how these
71b4a17a 558 * numbers relate to one another. The only thing is states explicitly
936c450a
FF
559 * is:
560 * real_total = real_process + real_free + numperm + real_system
561 *
562 * Another segmentation, which would be closer to the numbers reported
563 * by the "svmon" utility, would be:
564 * real_total = real_free + real_inuse
565 * real_inuse = "active" + real_pinned + numperm
566 */
8ec9a545
FF
567 values[STATE_FREE] = (gauge_t)(pmemory.real_free * pagesize);
568 values[STATE_CACHED] = (gauge_t)(pmemory.numperm * pagesize);
569 values[STATE_KERNEL] = (gauge_t)(pmemory.real_system * pagesize);
570 values[STATE_USED] = (gauge_t)(pmemory.real_process * pagesize);
f1b812b3 571#endif /* HAVE_PERFSTAT */
293819d0 572
307c875e 573 return 0;
577e34aa
FF
574} /* }}} int memory_read_internal */
575
936c450a 576static int memory_read(void) /* {{{ */
577e34aa 577{
8ec9a545
FF
578 gauge_t values[STATE_MAX] = {0};
579 for (size_t i = 0; i < STATE_MAX; i++) {
71b4a17a
FF
580 values[i] = NAN;
581 }
577e34aa 582
71b4a17a
FF
583 int status = memory_read_internal(values);
584 if (status != 0) {
585 return status;
586 }
577e34aa 587
71b4a17a 588 return memory_dispatch(values);
577e34aa 589} /* }}} int memory_read */
7fa270a1 590
936c450a
FF
591void module_register(void) {
592 plugin_register_complex_config("memory", memory_config);
593 plugin_register_init("memory", memory_init);
594 plugin_register_read("memory", memory_read);
2f0dfdda 595} /* void module_register */