freebsd branch: swap plugin: Use `sysctlnametomib' to query the mib if we don't know it.
[collectd.git] / src / swap.c
1 /**
2  * collectd - src/swap.c
3  * Copyright (C) 2005,2006  Florian octo Forster
4  *
5  * This program is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License as published by the
7  * Free Software Foundation; either version 2 of the License, or (at your
8  * option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
18  *
19  * Authors:
20  *   Florian octo Forster <octo at verplant.org>
21  **/
22
23 #include "collectd.h"
24 #include "common.h"
25 #include "plugin.h"
26
27 #if HAVE_SYS_SWAP_H
28 # include <sys/swap.h>
29 #endif
30 #if HAVE_SYS_PARAM_H
31 #  include <sys/param.h>
32 #endif
33 #if HAVE_SYS_SYSCTL_H
34 #  include <sys/sysctl.h>
35 #endif
36
37 #define MODULE_NAME "swap"
38
39 #if KERNEL_LINUX || HAVE_LIBKSTAT || HAVE_SYS_SYSCTL_H || HAVE_LIBSTATGRAB
40 # define SWAP_HAVE_READ 1
41 #else
42 # define SWAP_HAVE_READ 0
43 #endif
44
45 #undef  MAX
46 #define MAX(x,y) ((x) > (y) ? (x) : (y))
47
48 static char *swap_file = "swap.rrd";
49
50 /* 1099511627776 == 1TB ought to be enough for anyone ;) */
51 static char *ds_def[] =
52 {
53         "DS:used:GAUGE:"COLLECTD_HEARTBEAT":0:1099511627776",
54         "DS:free:GAUGE:"COLLECTD_HEARTBEAT":0:1099511627776",
55         "DS:cached:GAUGE:"COLLECTD_HEARTBEAT":0:1099511627776",
56         "DS:resv:GAUGE:"COLLECTD_HEARTBEAT":0:1099511627776",
57         NULL
58 };
59 static int ds_num = 4;
60
61 #if KERNEL_LINUX
62 /* No global variables */
63 /* #endif KERNEL_LINUX */
64
65 #elif HAVE_LIBKSTAT
66 static int pagesize;
67 static kstat_t *ksp;
68 /* #endif HAVE_LIBKSTAT */
69
70 #elif HAVE_SYS_SYSCTL_H
71 /* No global variables */
72 /* #endif HAVE_SYS_SYSCTL_H */
73
74 #elif HAVE_LIBSTATGRAB
75 /* No global variables */
76 #endif /* HAVE_LIBSTATGRAB */
77
78 static void swap_init (void)
79 {
80 #if KERNEL_LINUX
81         /* No init stuff */
82 /* #endif KERNEL_LINUX */
83
84 #elif HAVE_LIBKSTAT
85         /* getpagesize(3C) tells me this does not fail.. */
86         pagesize = getpagesize ();
87         if (get_kstat (&ksp, "unix", 0, "system_pages"))
88                 ksp = NULL;
89 /* #endif HAVE_LIBKSTAT */
90
91 #elif HAVE_SYS_SYSCTL_H
92         /* No init stuff */
93 /* #endif HAVE_SYS_SYSCTL_H */
94
95 #elif HAVE_LIBSTATGRAB
96         /* No init stuff */
97 #endif /* HAVE_LIBSTATGRAB */
98
99         return;
100 }
101
102 static void swap_write (char *host, char *inst, char *val)
103 {
104         rrd_update_file (host, swap_file, val, ds_def, ds_num);
105 }
106
107 #if SWAP_HAVE_READ
108 static void swap_submit (unsigned long long swap_used,
109                 unsigned long long swap_free,
110                 unsigned long long swap_cached,
111                 unsigned long long swap_resv)
112 {
113         char buffer[512];
114
115         if (snprintf (buffer, 512, "%u:%llu:%llu:%llu:%llu", (unsigned int) curtime,
116                                 swap_used, swap_free, swap_cached, swap_resv) >= 512)
117                 return;
118
119         plugin_submit (MODULE_NAME, "-", buffer);
120 }
121
122 static void swap_read (void)
123 {
124 #if KERNEL_LINUX
125         FILE *fh;
126         char buffer[1024];
127         
128         char *fields[8];
129         int numfields;
130
131         unsigned long long swap_used   = 0LL;
132         unsigned long long swap_cached = 0LL;
133         unsigned long long swap_free   = 0LL;
134         unsigned long long swap_total  = 0LL;
135
136         if ((fh = fopen ("/proc/meminfo", "r")) == NULL)
137         {
138                 syslog (LOG_WARNING, "memory: fopen: %s", strerror (errno));
139                 return;
140         }
141
142         while (fgets (buffer, 1024, fh) != NULL)
143         {
144                 unsigned long long *val = NULL;
145
146                 if (strncasecmp (buffer, "SwapTotal:", 10) == 0)
147                         val = &swap_total;
148                 else if (strncasecmp (buffer, "SwapFree:", 9) == 0)
149                         val = &swap_free;
150                 else if (strncasecmp (buffer, "SwapCached:", 11) == 0)
151                         val = &swap_cached;
152                 else
153                         continue;
154
155                 numfields = strsplit (buffer, fields, 8);
156
157                 if (numfields < 2)
158                         continue;
159
160                 *val = atoll (fields[1]) * 1024LL;
161         }
162
163         if (fclose (fh))
164                 syslog (LOG_WARNING, "memory: fclose: %s", strerror (errno));
165
166         if ((swap_total == 0LL) || ((swap_free + swap_cached) > swap_total))
167                 return;
168
169         swap_used = swap_total - (swap_free + swap_cached);
170
171         swap_submit (swap_used, swap_free, swap_cached, -1LL);
172 /* #endif KERNEL_LINUX */
173
174 #elif HAVE_LIBKSTAT
175         unsigned long long swap_alloc;
176         unsigned long long swap_resv;
177         unsigned long long swap_avail;
178         /* unsigned long long swap_free; */
179
180         long long availrmem;
181         long long swapfs_minfree;
182
183         struct anoninfo ai;
184
185         if (swapctl (SC_AINFO, &ai) == -1)
186                 return;
187
188         availrmem      = get_kstat_value (ksp, "availrmem");
189         swapfs_minfree = get_kstat_value (ksp, "minfree");
190
191         if ((availrmem < 0LL) || (swapfs_minfree < 0LL))
192                 return;
193
194         /* 
195          * Calculations learned by reading
196          * http://www.itworld.com/Comp/2377/UIR980701perf/
197          *
198          * swap_resv += ani_resv
199          * swap_alloc += MAX(ani_resv, ani_max) - ani_free
200          * swap_avail += MAX(ani_max - ani_resv, 0) + (availrmem - swapfs_minfree)
201          * swap_free += ani_free + (availrmem - swapfs_minfree)
202          *
203          * To clear up the terminology a bit:
204          * resv  = reserved (but not neccessarily used)
205          * alloc = used     (neccessarily reserved)
206          * avail = not reserved  (neccessarily free)
207          * free  = not allocates (possibly reserved)
208          */
209         swap_resv  = pagesize * ai.ani_resv;
210         swap_alloc = pagesize * (MAX(ai.ani_resv, ai.ani_max) - ai.ani_free);
211         swap_avail = pagesize * (MAX(ai.ani_max - ai.ani_resv, 0) + (availrmem - swapfs_minfree));
212         /* swap_free  = pagesize * (ai.ani_free + (availrmem - swapfs_minfree)); */
213
214         swap_submit (swap_alloc, swap_avail, -1LL, swap_resv - swap_alloc);
215 /* #endif HAVE_LIBKSTAT */
216
217 #elif HAVE_SYS_SYSCTL_H
218         int              mib[3];
219         size_t           mib_len;
220         struct xsw_usage sw_usage;
221         size_t           sw_usage_len;
222         int              status;
223
224 #if defined(VM_SWAPUSAGE)
225         mib_len = 2;
226         mib[0]  = CTL_VM;
227         mib[1]  = VM_SWAPUSAGE;
228 #else
229         mib_len = 3;
230         if ((status = sysctlnametomib ("vm.swap_info", mib, &mib_len)) < 0)
231         {
232                 syslog (LOG_WARN, "swap plugin: sysctlnametomib failed: %s",
233                                 strerror (errno));
234                 return;
235         }
236 #endif
237
238         sw_usage_len = sizeof (struct xsw_usage);
239
240         if (sysctl (mib, mib_len, &sw_usage, &sw_usage_len, NULL, 0) != 0)
241                 return;
242
243         /* The returned values are bytes. */
244         swap_submit (sw_usage.xsu_used, sw_usage.xsu_avail, -1LL, -1LL);
245 /* #endif HAVE_SYS_SYSCTL_H */
246
247 #elif HAVE_LIBSTATGRAB
248         sg_swap_stats *swap;
249
250         if ((swap = sg_get_swap_stats ()) != NULL)
251                 swap_submit (swap->used, swap->free, -1LL, -1LL);
252 #endif /* HAVE_LIBSTATGRAB */
253 }
254 #else
255 # define swap_read NULL
256 #endif /* SWAP_HAVE_READ */
257
258 void module_register (void)
259 {
260         plugin_register (MODULE_NAME, swap_init, swap_read, swap_write);
261 }
262
263 #undef MODULE_NAME