1 /**
2 * collectd - src/swap.c
3 * Copyright (C) 2005-2014 Florian octo Forster
4 * Copyright (C) 2009 Stefan Völkel
5 * Copyright (C) 2009 Manuel Sanmartin
6 * Copyright (C) 2010 Aurélien Reynaud
7 *
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; only version 2 of the License is applicable.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 *
21 * Authors:
22 * Florian octo Forster <octo at collectd.org>
23 * Manuel Sanmartin
24 * Aurélien Reynaud <collectd at wattapower.net>
25 **/
26
27 #if HAVE_CONFIG_H
28 #include "config.h"
29 #undef HAVE_CONFIG_H
30 #endif
31 /* avoid swap.h error "Cannot use swapctl in the large files compilation
32 * environment" */
33 #if HAVE_SYS_SWAP_H && !defined(_LP64) && _FILE_OFFSET_BITS == 64
34 #undef _FILE_OFFSET_BITS
35 #undef _LARGEFILE64_SOURCE
36 #endif
37
38 #include "collectd.h"
39
40 #include "plugin.h"
41 #include "utils/common/common.h"
42
43 #if HAVE_SYS_SWAP_H
44 #include <sys/swap.h>
45 #endif
46 #if HAVE_VM_ANON_H
47 #include <vm/anon.h>
48 #endif
49 #if HAVE_SYS_PARAM_H
50 #include <sys/param.h>
51 #endif
52 #if (defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTLBYNAME)) || \
53 defined(__OpenBSD__)
54 /* implies BSD variant */
55 #include <sys/sysctl.h>
56 #endif
57 #if HAVE_SYS_DKSTAT_H
58 #include <sys/dkstat.h>
59 #endif
60 #if HAVE_KVM_H
61 #include <kvm.h>
62 #endif
63
64 #if HAVE_STATGRAB_H
65 #include <statgrab.h>
66 #endif
67
68 #if HAVE_PERFSTAT
69 #include <libperfstat.h>
70 #include <sys/protosw.h>
71 #endif
72
73 #undef MAX
74 #define MAX(x, y) ((x) > (y) ? (x) : (y))
75
76 #if KERNEL_LINUX
77 #define SWAP_HAVE_REPORT_BY_DEVICE 1
78 static derive_t pagesize;
79 static bool report_bytes;
80 static bool report_by_device;
81 /* #endif KERNEL_LINUX */
82
83 #elif HAVE_SWAPCTL && (HAVE_SWAPCTL_TWO_ARGS || HAVE_SWAPCTL_THREE_ARGS)
84 #define SWAP_HAVE_REPORT_BY_DEVICE 1
85 static derive_t pagesize;
86 #if KERNEL_NETBSD
87 static _Bool report_bytes = 0;
88 #endif
89 static bool report_by_device;
90 /* #endif HAVE_SWAPCTL && HAVE_SWAPCTL_TWO_ARGS */
91
92 #elif HAVE_SWAPCTL && HAVE_SWAPCTL_THREE_ARGS
93 /* No global variables */
94 /* #endif HAVE_SWAPCTL && HAVE_SWAPCTL_THREE_ARGS */
95
96 #elif defined(VM_SWAPUSAGE)
97 /* No global variables */
98 /* #endif defined(VM_SWAPUSAGE) */
99
100 #elif HAVE_LIBKVM_GETSWAPINFO
101 static kvm_t *kvm_obj;
102 int kvm_pagesize;
103 /* #endif HAVE_LIBKVM_GETSWAPINFO */
104
105 #elif HAVE_LIBSTATGRAB
106 /* No global variables */
107 /* #endif HAVE_LIBSTATGRAB */
108
109 #elif HAVE_PERFSTAT
110 static int pagesize;
111 /*# endif HAVE_PERFSTAT */
112
113 #else
114 #error "No applicable input method."
115 #endif /* HAVE_LIBSTATGRAB */
116
117 static bool values_absolute = true;
118 static bool values_percentage;
119 static bool report_io = true;
120
swap_config(oconfig_item_t * ci)121 static int swap_config(oconfig_item_t *ci) /* {{{ */
122 {
123 for (int i = 0; i < ci->children_num; i++) {
124 oconfig_item_t *child = ci->children + i;
125 if (strcasecmp("ReportBytes", child->key) == 0)
126 #if KERNEL_LINUX || KERNEL_NETBSD
127 cf_util_get_boolean(child, &report_bytes);
128 #else
129 WARNING("swap plugin: The \"ReportBytes\" option "
130 "is only valid under Linux. "
131 "The option is going to be ignored.");
132 #endif
133 else if (strcasecmp("ReportByDevice", child->key) == 0)
134 #if SWAP_HAVE_REPORT_BY_DEVICE
135 cf_util_get_boolean(child, &report_by_device);
136 #else
137 WARNING("swap plugin: The \"ReportByDevice\" option "
138 "is not supported on this platform. "
139 "The option is going to be ignored.");
140 #endif /* SWAP_HAVE_REPORT_BY_DEVICE */
141 else if (strcasecmp("ValuesAbsolute", child->key) == 0)
142 cf_util_get_boolean(child, &values_absolute);
143 else if (strcasecmp("ValuesPercentage", child->key) == 0)
144 cf_util_get_boolean(child, &values_percentage);
145 else if (strcasecmp("ReportIO", child->key) == 0)
146 cf_util_get_boolean(child, &report_io);
147 else
148 WARNING("swap plugin: Unknown config option: \"%s\"", child->key);
149 }
150
151 return 0;
152 } /* }}} int swap_config */
153
swap_init(void)154 static int swap_init(void) /* {{{ */
155 {
156 #if KERNEL_LINUX
157 pagesize = (derive_t)sysconf(_SC_PAGESIZE);
158 /* #endif KERNEL_LINUX */
159
160 #elif HAVE_SWAPCTL && (HAVE_SWAPCTL_TWO_ARGS || HAVE_SWAPCTL_THREE_ARGS)
161 /* getpagesize(3C) tells me this does not fail.. */
162 pagesize = (derive_t)getpagesize();
163 /* #endif HAVE_SWAPCTL */
164
165 #elif defined(VM_SWAPUSAGE)
166 /* No init stuff */
167 /* #endif defined(VM_SWAPUSAGE) */
168
169 #elif HAVE_LIBKVM_GETSWAPINFO
170 char errbuf[_POSIX2_LINE_MAX];
171
172 if (kvm_obj != NULL) {
173 kvm_close(kvm_obj);
174 kvm_obj = NULL;
175 }
176
177 kvm_pagesize = getpagesize();
178
179 kvm_obj = kvm_openfiles(NULL, "/dev/null", NULL, O_RDONLY, errbuf);
180
181 if (kvm_obj == NULL) {
182 ERROR("swap plugin: kvm_openfiles failed, %s", errbuf);
183 return -1;
184 }
185 /* #endif HAVE_LIBKVM_GETSWAPINFO */
186
187 #elif HAVE_LIBSTATGRAB
188 /* No init stuff */
189 /* #endif HAVE_LIBSTATGRAB */
190
191 #elif HAVE_PERFSTAT
192 pagesize = getpagesize();
193 #endif /* HAVE_PERFSTAT */
194
195 return 0;
196 } /* }}} int swap_init */
197
swap_submit_usage(char const * plugin_instance,gauge_t used,gauge_t free,char const * other_name,gauge_t other_value)198 static void swap_submit_usage(char const *plugin_instance, /* {{{ */
199 gauge_t used, gauge_t free,
200 char const *other_name, gauge_t other_value) {
201 value_list_t vl = VALUE_LIST_INIT;
202
203 vl.values = &(value_t){.gauge = NAN};
204 vl.values_len = 1;
205 sstrncpy(vl.plugin, "swap", sizeof(vl.plugin));
206 if (plugin_instance != NULL)
207 sstrncpy(vl.plugin_instance, plugin_instance, sizeof(vl.plugin_instance));
208 sstrncpy(vl.type, "swap", sizeof(vl.type));
209
210 if (values_absolute)
211 plugin_dispatch_multivalue(&vl, false, DS_TYPE_GAUGE, "used", used, "free",
212 free, other_name, other_value, NULL);
213 if (values_percentage)
214 plugin_dispatch_multivalue(&vl, true, DS_TYPE_GAUGE, "used", used, "free",
215 free, other_name, other_value, NULL);
216 } /* }}} void swap_submit_usage */
217
218 #if KERNEL_LINUX || HAVE_PERFSTAT || KERNEL_NETBSD
219 __attribute__((nonnull(1))) static void
swap_submit_derive(char const * type_instance,derive_t value)220 swap_submit_derive(char const *type_instance, /* {{{ */
221 derive_t value) {
222 value_list_t vl = VALUE_LIST_INIT;
223
224 vl.values = &(value_t){.derive = value};
225 vl.values_len = 1;
226 sstrncpy(vl.plugin, "swap", sizeof(vl.plugin));
227 sstrncpy(vl.type, "swap_io", sizeof(vl.type));
228 sstrncpy(vl.type_instance, type_instance, sizeof(vl.type_instance));
229
230 plugin_dispatch_values(&vl);
231 } /* }}} void swap_submit_derive */
232 #endif
233
234 #if KERNEL_LINUX
swap_read_separate(void)235 static int swap_read_separate(void) /* {{{ */
236 {
237 FILE *fh;
238 char buffer[1024];
239
240 fh = fopen("/proc/swaps", "r");
241 if (fh == NULL) {
242 WARNING("swap plugin: fopen (/proc/swaps) failed: %s", STRERRNO);
243 return -1;
244 }
245
246 while (fgets(buffer, sizeof(buffer), fh) != NULL) {
247 char *fields[8];
248 int numfields;
249 char *endptr;
250
251 char path[PATH_MAX];
252 gauge_t total;
253 gauge_t used;
254
255 numfields = strsplit(buffer, fields, STATIC_ARRAY_SIZE(fields));
256 if (numfields != 5)
257 continue;
258
259 sstrncpy(path, fields[0], sizeof(path));
260 escape_slashes(path, sizeof(path));
261
262 errno = 0;
263 endptr = NULL;
264 total = strtod(fields[2], &endptr);
265 if ((endptr == fields[2]) || (errno != 0))
266 continue;
267
268 errno = 0;
269 endptr = NULL;
270 used = strtod(fields[3], &endptr);
271 if ((endptr == fields[3]) || (errno != 0))
272 continue;
273
274 if (total < used)
275 continue;
276
277 swap_submit_usage(path, used * 1024.0, (total - used) * 1024.0, NULL, NAN);
278 }
279
280 fclose(fh);
281
282 return 0;
283 } /* }}} int swap_read_separate */
284
swap_read_combined(void)285 static int swap_read_combined(void) /* {{{ */
286 {
287 FILE *fh;
288 char buffer[1024];
289
290 gauge_t swap_used = NAN;
291 gauge_t swap_cached = NAN;
292 gauge_t swap_free = NAN;
293 gauge_t swap_total = NAN;
294
295 fh = fopen("/proc/meminfo", "r");
296 if (fh == NULL) {
297 WARNING("swap plugin: fopen (/proc/meminfo) failed: %s", STRERRNO);
298 return -1;
299 }
300
301 while (fgets(buffer, sizeof(buffer), fh) != NULL) {
302 char *fields[8];
303 int numfields;
304
305 numfields = strsplit(buffer, fields, STATIC_ARRAY_SIZE(fields));
306 if (numfields < 2)
307 continue;
308
309 if (strcasecmp(fields[0], "SwapTotal:") == 0)
310 strtogauge(fields[1], &swap_total);
311 else if (strcasecmp(fields[0], "SwapFree:") == 0)
312 strtogauge(fields[1], &swap_free);
313 else if (strcasecmp(fields[0], "SwapCached:") == 0)
314 strtogauge(fields[1], &swap_cached);
315 }
316
317 fclose(fh);
318
319 if (isnan(swap_total) || isnan(swap_free))
320 return ENOENT;
321
322 /* Some systems, OpenVZ for example, don't provide SwapCached. */
323 if (isnan(swap_cached))
324 swap_used = swap_total - swap_free;
325 else
326 swap_used = swap_total - (swap_free + swap_cached);
327 assert(!isnan(swap_used));
328
329 if (swap_used < 0.0)
330 return EINVAL;
331
332 swap_submit_usage(NULL, swap_used * 1024.0, swap_free * 1024.0,
333 isnan(swap_cached) ? NULL : "cached",
334 isnan(swap_cached) ? NAN : swap_cached * 1024.0);
335 return 0;
336 } /* }}} int swap_read_combined */
337
swap_read_io(void)338 static int swap_read_io(void) /* {{{ */
339 {
340 char buffer[1024];
341
342 uint8_t have_data = 0;
343 derive_t swap_in = 0;
344 derive_t swap_out = 0;
345
346 FILE *fh = fopen("/proc/vmstat", "r");
347 if (fh == NULL) {
348 WARNING("swap: fopen(/proc/vmstat): %s", STRERRNO);
349 return -1;
350 }
351
352 while (fgets(buffer, sizeof(buffer), fh) != NULL) {
353 char *fields[8];
354 int numfields = strsplit(buffer, fields, STATIC_ARRAY_SIZE(fields));
355
356 if (numfields != 2)
357 continue;
358
359 if (strcasecmp("pswpin", fields[0]) == 0) {
360 strtoderive(fields[1], &swap_in);
361 have_data |= 0x01;
362 } else if (strcasecmp("pswpout", fields[0]) == 0) {
363 strtoderive(fields[1], &swap_out);
364 have_data |= 0x02;
365 }
366 } /* while (fgets) */
367
368 fclose(fh);
369
370 if (have_data != 0x03)
371 return ENOENT;
372
373 if (report_bytes) {
374 swap_in = swap_in * pagesize;
375 swap_out = swap_out * pagesize;
376 }
377
378 swap_submit_derive("in", swap_in);
379 swap_submit_derive("out", swap_out);
380
381 return 0;
382 } /* }}} int swap_read_io */
383
swap_read(void)384 static int swap_read(void) /* {{{ */
385 {
386 if (report_by_device)
387 swap_read_separate();
388 else
389 swap_read_combined();
390
391 if (report_io)
392 swap_read_io();
393
394 return 0;
395 } /* }}} int swap_read */
396 /* #endif KERNEL_LINUX */
397
398 /*
399 * Under Solaris, two mechanisms can be used to read swap statistics, swapctl
400 * and kstat. The former reads physical space used on a device, the latter
401 * reports the view from the virtual memory system. It was decided that the
402 * kstat-based information should be moved to the "vmem" plugin, but nobody
403 * with enough Solaris experience was available at that time to do this. The
404 * code below is still there for your reference but it won't be activated in
405 * *this* plugin again. --octo
406 */
407 #elif 0 && HAVE_LIBKSTAT
408 /* kstat-based read function */
swap_read_kstat(void)409 static int swap_read_kstat(void) /* {{{ */
410 {
411 gauge_t swap_alloc;
412 gauge_t swap_resv;
413 gauge_t swap_avail;
414
415 struct anoninfo ai;
416
417 if (swapctl(SC_AINFO, &ai) == -1) {
418 ERROR("swap plugin: swapctl failed: %s", STRERRNO);
419 return -1;
420 }
421
422 /*
423 * Calculations from:
424 * http://cvs.opensolaris.org/source/xref/on/usr/src/cmd/swap/swap.c
425 * Also see:
426 * http://www.itworld.com/Comp/2377/UIR980701perf/ (outdated?)
427 * /usr/include/vm/anon.h
428 *
429 * In short, swap -s shows: allocated + reserved = used, available
430 *
431 * However, Solaris does not allow to allocated/reserved more than the
432 * available swap (physical memory + disk swap), so the pedant may
433 * prefer: allocated + unallocated = reserved, available
434 *
435 * We map the above to: used + resv = n/a, free
436 *
437 * Does your brain hurt yet? - Christophe Kalt
438 *
439 * Oh, and in case you wonder,
440 * swap_alloc = pagesize * ( ai.ani_max - ai.ani_free );
441 * can suffer from a 32bit overflow.
442 */
443 swap_alloc = (gauge_t)((ai.ani_max - ai.ani_free) * pagesize);
444 swap_resv = (gauge_t)((ai.ani_resv + ai.ani_free - ai.ani_max) * pagesize);
445 swap_avail = (gauge_t)((ai.ani_max - ai.ani_resv) * pagesize);
446
447 swap_submit_usage(NULL, swap_alloc, swap_avail, "reserved", swap_resv);
448 return 0;
449 } /* }}} int swap_read_kstat */
450 /* #endif 0 && HAVE_LIBKSTAT */
451
452 #elif HAVE_SWAPCTL && HAVE_SWAPCTL_TWO_ARGS
453 /* swapctl-based read function */
swap_read(void)454 static int swap_read(void) /* {{{ */
455 {
456 swaptbl_t *s;
457 char *s_paths;
458 int swap_num;
459 int status;
460
461 gauge_t avail = 0;
462 gauge_t total = 0;
463
464 swap_num = swapctl(SC_GETNSWP, NULL);
465 if (swap_num < 0) {
466 ERROR("swap plugin: swapctl (SC_GETNSWP) failed with status %i.", swap_num);
467 return -1;
468 } else if (swap_num == 0)
469 return 0;
470
471 /* Allocate and initialize the swaptbl_t structure */
472 s = malloc(swap_num * sizeof(swapent_t) + sizeof(struct swaptable));
473 if (s == NULL) {
474 ERROR("swap plugin: malloc failed.");
475 return -1;
476 }
477
478 /* Memory to store the path names. We only use these paths when the
479 * separate option has been configured, but it's easier to just
480 * allocate enough memory in any case. */
481 s_paths = calloc(swap_num, PATH_MAX);
482 if (s_paths == NULL) {
483 ERROR("swap plugin: calloc failed.");
484 sfree(s);
485 return -1;
486 }
487 for (int i = 0; i < swap_num; i++)
488 s->swt_ent[i].ste_path = s_paths + (i * PATH_MAX);
489 s->swt_n = swap_num;
490
491 status = swapctl(SC_LIST, s);
492 if (status < 0) {
493 ERROR("swap plugin: swapctl (SC_LIST) failed: %s", STRERRNO);
494 sfree(s_paths);
495 sfree(s);
496 return -1;
497 } else if (swap_num < status) {
498 /* more elements returned than requested */
499 ERROR("swap plugin: I allocated memory for %i structure%s, "
500 "but swapctl(2) claims to have returned %i. "
501 "I'm confused and will give up.",
502 swap_num, (swap_num == 1) ? "" : "s", status);
503 sfree(s_paths);
504 sfree(s);
505 return -1;
506 } else if (swap_num > status)
507 /* less elements returned than requested */
508 swap_num = status;
509
510 for (int i = 0; i < swap_num; i++) {
511 char path[PATH_MAX];
512 gauge_t this_total;
513 gauge_t this_avail;
514
515 if ((s->swt_ent[i].ste_flags & ST_INDEL) != 0)
516 continue;
517
518 this_total = (gauge_t)(s->swt_ent[i].ste_pages * pagesize);
519 this_avail = (gauge_t)(s->swt_ent[i].ste_free * pagesize);
520
521 /* Shortcut for the "combined" setting (default) */
522 if (!report_by_device) {
523 avail += this_avail;
524 total += this_total;
525 continue;
526 }
527
528 sstrncpy(path, s->swt_ent[i].ste_path, sizeof(path));
529 escape_slashes(path, sizeof(path));
530
531 swap_submit_usage(path, this_total - this_avail, this_avail, NULL, NAN);
532 } /* for (swap_num) */
533
534 if (total < avail) {
535 ERROR(
536 "swap plugin: Total swap space (%g) is less than free swap space (%g).",
537 total, avail);
538 sfree(s_paths);
539 sfree(s);
540 return -1;
541 }
542
543 /* If the "separate" option was specified (report_by_device == true) all
544 * values have already been dispatched from within the loop. */
545 if (!report_by_device)
546 swap_submit_usage(NULL, total - avail, avail, NULL, NAN);
547
548 sfree(s_paths);
549 sfree(s);
550 return 0;
551 } /* }}} int swap_read */
552 /* #endif HAVE_SWAPCTL && HAVE_SWAPCTL_TWO_ARGS */
553
554 #elif HAVE_SWAPCTL && HAVE_SWAPCTL_THREE_ARGS
555 #if KERNEL_NETBSD
556 #include <uvm/uvm_extern.h>
557
swap_read_io(void)558 static int swap_read_io(void) /* {{{ */
559 {
560 static int uvmexp_mib[] = {CTL_VM, VM_UVMEXP2};
561 struct uvmexp_sysctl uvmexp;
562 size_t ssize;
563 derive_t swap_in, swap_out;
564
565 ssize = sizeof(uvmexp);
566 memset(&uvmexp, 0, ssize);
567 if (sysctl(uvmexp_mib, __arraycount(uvmexp_mib), &uvmexp, &ssize, NULL, 0) ==
568 -1) {
569 char errbuf[1024];
570 WARNING("swap: sysctl for uvmexp failed: %s",
571 sstrerror(errno, errbuf, sizeof(errbuf)));
572 return (-1);
573 }
574
575 swap_in = uvmexp.pgswapin;
576 swap_out = uvmexp.pgswapout;
577
578 if (report_bytes) {
579 swap_in = swap_in * pagesize;
580 swap_out = swap_out * pagesize;
581 }
582
583 swap_submit_derive("in", swap_in);
584 swap_submit_derive("out", swap_out);
585
586 return (0);
587 } /* }}} */
588 #endif
589
swap_read(void)590 static int swap_read(void) /* {{{ */
591 {
592 struct swapent *swap_entries;
593 int swap_num;
594 int status;
595
596 gauge_t used = 0;
597 gauge_t total = 0;
598
599 swap_num = swapctl(SWAP_NSWAP, NULL, 0);
600 if (swap_num < 0) {
601 ERROR("swap plugin: swapctl (SWAP_NSWAP) failed with status %i.", swap_num);
602 return -1;
603 } else if (swap_num == 0)
604 return 0;
605
606 swap_entries = calloc(swap_num, sizeof(*swap_entries));
607 if (swap_entries == NULL) {
608 ERROR("swap plugin: calloc failed.");
609 return -1;
610 }
611
612 status = swapctl(SWAP_STATS, swap_entries, swap_num);
613 if (status != swap_num) {
614 ERROR("swap plugin: swapctl (SWAP_STATS) failed with status %i.", status);
615 sfree(swap_entries);
616 return -1;
617 }
618
619 #if defined(DEV_BSIZE) && (DEV_BSIZE > 0)
620 #define C_SWAP_BLOCK_SIZE ((gauge_t)DEV_BSIZE)
621 #else
622 #define C_SWAP_BLOCK_SIZE 512.0
623 #endif
624
625 /* TODO: Report per-device stats. The path name is available from
626 * swap_entries[i].se_path */
627 for (int i = 0; i < swap_num; i++) {
628 char path[PATH_MAX];
629 gauge_t this_used;
630 gauge_t this_total;
631
632 if ((swap_entries[i].se_flags & SWF_ENABLE) == 0)
633 continue;
634
635 this_used = ((gauge_t)swap_entries[i].se_inuse) * C_SWAP_BLOCK_SIZE;
636 this_total = ((gauge_t)swap_entries[i].se_nblks) * C_SWAP_BLOCK_SIZE;
637
638 /* Shortcut for the "combined" setting (default) */
639 if (!report_by_device) {
640 used += this_used;
641 total += this_total;
642 continue;
643 }
644
645 sstrncpy(path, swap_entries[i].se_path, sizeof(path));
646 escape_slashes(path, sizeof(path));
647
648 swap_submit_usage(path, this_used, this_total - this_used, NULL, NAN);
649 } /* for (swap_num) */
650
651 if (total < used) {
652 ERROR(
653 "swap plugin: Total swap space (%g) is less than used swap space (%g).",
654 total, used);
655 sfree(swap_entries);
656 return -1;
657 }
658
659 swap_submit_usage(NULL, used, total - used, NULL, NAN);
660 /* If the "separate" option was specified (report_by_device == 1), all
661 * values have already been dispatched from within the loop. */
662 if (!report_by_device)
663 swap_submit_usage(NULL, used, total - used, NULL, NAN);
664
665 sfree(swap_entries);
666 #if KERNEL_NETBSD
667 swap_read_io();
668 #endif
669 return 0;
670 } /* }}} int swap_read */
671 /* #endif HAVE_SWAPCTL && HAVE_SWAPCTL_THREE_ARGS */
672
673 #elif defined(VM_SWAPUSAGE)
swap_read(void)674 static int swap_read(void) /* {{{ */
675 {
676 int mib[3];
677 size_t mib_len;
678 struct xsw_usage sw_usage;
679 size_t sw_usage_len;
680
681 mib_len = 2;
682 mib[0] = CTL_VM;
683 mib[1] = VM_SWAPUSAGE;
684
685 sw_usage_len = sizeof(struct xsw_usage);
686
687 if (sysctl(mib, mib_len, &sw_usage, &sw_usage_len, NULL, 0) != 0)
688 return -1;
689
690 /* The returned values are bytes. */
691 swap_submit_usage(NULL, (gauge_t)sw_usage.xsu_used,
692 (gauge_t)sw_usage.xsu_avail, NULL, NAN);
693
694 return 0;
695 } /* }}} int swap_read */
696 /* #endif VM_SWAPUSAGE */
697
698 #elif HAVE_LIBKVM_GETSWAPINFO
swap_read(void)699 static int swap_read(void) /* {{{ */
700 {
701 struct kvm_swap data_s;
702 int status;
703
704 gauge_t used;
705 gauge_t total;
706
707 if (kvm_obj == NULL)
708 return -1;
709
710 /* only one structure => only get the grand total, no details */
711 status = kvm_getswapinfo(kvm_obj, &data_s, 1, 0);
712 if (status == -1)
713 return -1;
714
715 total = (gauge_t)data_s.ksw_total;
716 used = (gauge_t)data_s.ksw_used;
717
718 total *= (gauge_t)kvm_pagesize;
719 used *= (gauge_t)kvm_pagesize;
720
721 swap_submit_usage(NULL, used, total - used, NULL, NAN);
722
723 return 0;
724 } /* }}} int swap_read */
725 /* #endif HAVE_LIBKVM_GETSWAPINFO */
726
727 #elif HAVE_LIBSTATGRAB
swap_read(void)728 static int swap_read(void) /* {{{ */
729 {
730 sg_swap_stats *swap;
731
732 swap = sg_get_swap_stats();
733 if (swap == NULL)
734 return -1;
735
736 swap_submit_usage(NULL, (gauge_t)swap->used, (gauge_t)swap->free, NULL, NAN);
737
738 return 0;
739 } /* }}} int swap_read */
740 /* #endif HAVE_LIBSTATGRAB */
741
742 #elif HAVE_PERFSTAT
swap_read(void)743 static int swap_read(void) /* {{{ */
744 {
745 perfstat_memory_total_t pmemory = {0};
746 int status;
747
748 gauge_t total;
749 gauge_t free;
750 gauge_t reserved;
751
752 status =
753 perfstat_memory_total(NULL, &pmemory, sizeof(perfstat_memory_total_t), 1);
754 if (status < 0) {
755 WARNING("swap plugin: perfstat_memory_total failed: %s", STRERRNO);
756 return -1;
757 }
758
759 total = (gauge_t)(pmemory.pgsp_total * pagesize);
760 free = (gauge_t)(pmemory.pgsp_free * pagesize);
761 reserved = (gauge_t)(pmemory.pgsp_rsvd * pagesize);
762
763 swap_submit_usage(NULL, total - free, free, "reserved", reserved);
764
765 if (report_io) {
766 swap_submit_derive("in", (derive_t)pmemory.pgspins * pagesize);
767 swap_submit_derive("out", (derive_t)pmemory.pgspouts * pagesize);
768 }
769
770 return 0;
771 } /* }}} int swap_read */
772 #endif /* HAVE_PERFSTAT */
773
module_register(void)774 void module_register(void) {
775 plugin_register_complex_config("swap", swap_config);
776 plugin_register_init("swap", swap_init);
777 plugin_register_read("swap", swap_read);
778 } /* void module_register */
779