1 /*
2     KSysGuard, the KDE System Guard
3 
4     Copyright (c) 2010-2011 David Naylor <naylor.b.david@gmail.com>
5     Copyright (c) 1999-2000 Hans Petter Bieker <bieker@kde.org>
6     Copyright (c) 1999 Chris Schlaeger <cs@kde.org>
7 
8     This program is free software; you can redistribute it and/or modify
9     it under the terms of the GNU General Public License as published by
10     the Free Software Foundation; either version 2 of the License, or
11     (at your option) any later version.
12 
13     This program is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU General Public License for more details.
17 
18     You should have received a copy of the GNU General Public License
19     along with this program; if not, write to the Free Software
20     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 
22 */
23 
24 #include <sys/types.h>
25 #include <sys/sysctl.h>
26 
27 #include <fcntl.h>
28 #include <limits.h>
29 #include <stdio.h>
30 #include <unistd.h>
31 
32 #include <vm/vm_param.h>
33 
34 #include "Command.h"
35 #include "Memory.h"
36 #include "ksysguardd.h"
37 
38 #define MEM_ACTIVE 0
39 #define MEM_INACTIVE 1
40 #define MEM_WIRED 2
41 #define MEM_CACHED 3
42 #define MEM_BUFFERED 4
43 #define MEM_FREE 5
44 #define MEM_TOTAL 6
45 
46 static size_t memory_stats[7];
47 
48 #define SWAP_IN 0
49 #define SWAP_OUT 1
50 #define SWAP_USED 2
51 #define SWAP_FREE 3
52 #define SWAP_TOTAL 4
53 
54 static size_t swap_stats[5];
55 static size_t swap_old[2];
56 
57 static int pagesize;
58 
59 void kvm_getswapinfo_sysctl(size_t *ksw_used, size_t *ksw_total);
60 
initMemory(struct SensorModul * sm)61 void initMemory(struct SensorModul* sm)
62 {
63     char *nlistf = NULL;
64     char *memf = NULL;
65     char buf[_POSIX2_LINE_MAX];
66 
67     pagesize = getpagesize();
68 
69     registerMonitor("mem/physical/active", "integer", printMActive, printMActiveInfo, sm);
70     registerMonitor("mem/physical/inactive", "integer", printMInactive, printMInactiveInfo, sm);
71     registerMonitor("mem/physical/application", "integer", printMApplication, printMApplicationInfo, sm);
72     registerMonitor("mem/physical/wired", "integer", printMWired, printMWiredInfo, sm);
73     registerMonitor("mem/physical/cached", "integer", printMCached, printMCachedInfo, sm);
74     registerMonitor("mem/physical/buf", "integer", printMBuffers, printMBuffersInfo, sm);
75     registerMonitor("mem/physical/free", "integer", printMFree, printMFreeInfo, sm);
76     registerMonitor("mem/physical/used", "integer", printMUsed, printMUsedInfo, sm);
77 
78     registerMonitor("mem/swap/free", "integer", printSwapFree, printSwapFreeInfo, sm);
79     registerMonitor("mem/swap/used", "integer", printSwapUsed, printSwapUsedInfo, sm);
80     registerMonitor("mem/swap/pageIn", "integer", printSwapIn, printSwapInInfo, sm);
81     registerMonitor("mem/swap/pageOut", "integer", printSwapOut, printSwapOutInfo, sm);
82 
83     registerLegacyMonitor("cpu/pageIn", "float", printSwapIn, printSwapInInfo, sm);
84     registerLegacyMonitor("cpu/pageOut", "float", printSwapOut, printSwapOutInfo, sm);
85 
86     swap_old[SWAP_IN] = -1;
87     swap_old[SWAP_OUT] = -1;
88 
89     updateMemory();
90 }
91 
exitMemory(void)92 void exitMemory(void)
93 {
94     removeMonitor("mem/physical/active");
95     removeMonitor("mem/physical/inactive");
96     removeMonitor("mem/physical/application");
97     removeMonitor("mem/physical/wired");
98     removeMonitor("mem/physical/cached");
99     removeMonitor("mem/physical/buf");
100     removeMonitor("mem/physical/free");
101     removeMonitor("mem/physical/used");
102 
103     removeMonitor("mem/swap/free");
104     removeMonitor("mem/swap/used");
105     removeMonitor("mem/swap/pageIn");
106     removeMonitor("mem/swap/pageOut");
107 
108     removeMonitor("cpu/pageIn");
109     removeMonitor("cpu/pageOut");
110 }
111 
updateMemory(void)112 int updateMemory(void)
113 {
114     size_t len, ksw_used, ksw_total;
115     int swapin, swapout;
116 
117 #define CONVERT(v)    ((quad_t)(v) * pagesize / 1024)
118 
119 #define GETSYSCTL(mib, var)                        \
120     len = sizeof(var);                        \
121     sysctlbyname(mib, &var, &len, NULL, 0);
122 
123 #define GETPAGESYSCTL(mib, var)                        \
124     GETSYSCTL(mib, var)                        \
125     var = CONVERT(var);
126 
127 #define GETMEMSYSCTL(mib, var)                        \
128     GETSYSCTL(mib, var)                        \
129     var /= 1024;
130 
131     /*
132      * Memory
133      */
134     GETPAGESYSCTL("vm.stats.vm.v_active_count", memory_stats[MEM_ACTIVE])
135     GETPAGESYSCTL("vm.stats.vm.v_inactive_count", memory_stats[MEM_INACTIVE])
136     GETPAGESYSCTL("vm.stats.vm.v_wire_count", memory_stats[MEM_WIRED])
137     GETPAGESYSCTL("vm.stats.vm.v_cache_count", memory_stats[MEM_CACHED])
138     GETPAGESYSCTL("vm.stats.vm.v_free_count", memory_stats[MEM_FREE])
139     GETMEMSYSCTL("vfs.bufspace", memory_stats[MEM_BUFFERED])
140     GETMEMSYSCTL("hw.physmem", memory_stats[MEM_TOTAL])
141 
142     /*
143      * Swap
144      */
145     GETSYSCTL("vm.stats.vm.v_swappgsin", swapin);
146     GETSYSCTL("vm.stats.vm.v_swappgsout", swapout);
147 
148     if (swap_old[SWAP_IN] < 0) {
149         swap_stats[SWAP_IN] = 0;
150         swap_stats[SWAP_OUT] = 0;
151     } else {
152         swap_stats[SWAP_IN] = CONVERT(swapin - swap_old[SWAP_IN]);
153         swap_stats[SWAP_OUT] = CONVERT(swapout - swap_old[SWAP_OUT]);
154     }
155 
156     /* only for changes */
157     if (swap_stats[SWAP_IN] > 0 || swap_stats[SWAP_OUT] > 0 || swap_old[SWAP_IN] < 0) {
158         kvm_getswapinfo_sysctl(&ksw_used, &ksw_total);
159         swap_stats[SWAP_TOTAL] = CONVERT(ksw_total);
160         swap_stats[SWAP_USED] = CONVERT(ksw_used);
161         swap_stats[SWAP_FREE] = CONVERT(ksw_total - ksw_used);
162     }
163 
164     swap_old[SWAP_IN] = swapin;
165     swap_old[SWAP_OUT] = swapout;
166 
167     return 0;
168 
169 #undef CONVERT
170 #undef GETSYSCTL
171 #undef GETPAGESYSCTL
172 #undef GETMEMSYSCTL
173 }
174 
printMActive(const char * cmd)175 void printMActive(const char* cmd)
176 {
177     fprintf(CurrentClient, "%lu\n", memory_stats[MEM_ACTIVE]);
178 }
179 
printMActiveInfo(const char * cmd)180 void printMActiveInfo(const char* cmd)
181 {
182     fprintf(CurrentClient, "Active Memory\t0\t%lu\tKB\n", memory_stats[MEM_TOTAL]);
183 }
184 
printMInactive(const char * cmd)185 void printMInactive(const char* cmd)
186 {
187     fprintf(CurrentClient, "%lu\n", memory_stats[MEM_INACTIVE]);
188 }
189 
printMInactiveInfo(const char * cmd)190 void printMInactiveInfo(const char* cmd)
191 {
192     fprintf(CurrentClient, "Inactive Memory\t0\t%lu\tKB\n", memory_stats[MEM_TOTAL]);
193 }
194 
printMApplication(const char * cmd)195 void printMApplication(const char* cmd)
196 {
197     fprintf(CurrentClient, "%lu\n", memory_stats[MEM_ACTIVE] + memory_stats[MEM_INACTIVE]);
198 }
199 
printMApplicationInfo(const char * cmd)200 void printMApplicationInfo(const char* cmd)
201 {
202     fprintf(CurrentClient, "Application (Active and Inactive) Memory\t0\t%ld\tKB\n", memory_stats[MEM_TOTAL]);
203 }
204 
printMWired(const char * cmd)205 void printMWired(const char* cmd)
206 {
207     fprintf(CurrentClient, "%lu\n", memory_stats[MEM_WIRED]);
208 }
209 
printMWiredInfo(const char * cmd)210 void printMWiredInfo(const char* cmd)
211 {
212     fprintf(CurrentClient, "Wired Memory\t0\t%lu\tKB\n", memory_stats[MEM_TOTAL]);
213 }
214 
printMCached(const char * cmd)215 void printMCached(const char* cmd)
216 {
217     fprintf(CurrentClient, "%lu\n", memory_stats[MEM_CACHED]);
218 }
219 
printMCachedInfo(const char * cmd)220 void printMCachedInfo(const char* cmd)
221 {
222     fprintf(CurrentClient, "Cached Memory\t0\t%lu\tKB\n", memory_stats[MEM_TOTAL]);
223 }
224 
printMBuffers(const char * cmd)225 void printMBuffers(const char* cmd)
226 {
227     fprintf(CurrentClient, "%lu\n", memory_stats[MEM_BUFFERED]);
228 }
229 
printMBuffersInfo(const char * cmd)230 void printMBuffersInfo(const char* cmd)
231 {
232     fprintf(CurrentClient, "Buffer Memory\t0\t%lu\tKB\n", memory_stats[MEM_TOTAL]);
233 }
234 
printMFree(const char * cmd)235 void printMFree(const char* cmd)
236 {
237     fprintf(CurrentClient, "%lu\n", memory_stats[MEM_FREE]);
238 }
239 
printMFreeInfo(const char * cmd)240 void printMFreeInfo(const char* cmd)
241 {
242     fprintf(CurrentClient, "Free Memory\t0\t%lu\tKB\n", memory_stats[MEM_TOTAL]);
243 }
244 
printMUsed(const char * cmd)245 void printMUsed(const char* cmd)
246 {
247     fprintf(CurrentClient, "%lu\n", memory_stats[MEM_TOTAL] - memory_stats[MEM_FREE]);
248 }
249 
printMUsedInfo(const char * cmd)250 void printMUsedInfo(const char* cmd)
251 {
252     fprintf(CurrentClient, "Used Memory\t0\t%lu\tKB\n", memory_stats[MEM_TOTAL]);
253 }
254 
printSwapUsed(const char * cmd)255 void printSwapUsed(const char* cmd)
256 {
257     fprintf(CurrentClient, "%lu\n", swap_stats[SWAP_USED]);
258 }
259 
printSwapUsedInfo(const char * cmd)260 void printSwapUsedInfo(const char* cmd)
261 {
262     fprintf(CurrentClient, "Used Swap Memory\t0\t%lu\tKB\n", swap_stats[SWAP_TOTAL]);
263 }
264 
printSwapFree(const char * cmd)265 void printSwapFree(const char* cmd)
266 {
267     fprintf(CurrentClient, "%lu\n", swap_stats[SWAP_FREE]);
268 }
269 
printSwapFreeInfo(const char * cmd)270 void printSwapFreeInfo(const char* cmd)
271 {
272     fprintf(CurrentClient, "Free Swap Memory\t0\t%lu\tKB\n", swap_stats[SWAP_TOTAL]);
273 }
274 
printSwapIn(const char * cmd)275 void printSwapIn(const char* cmd)
276 {
277     fprintf(CurrentClient, "%lu\n", swap_stats[SWAP_IN]);
278 }
279 
printSwapInInfo(const char * cmd)280 void printSwapInInfo(const char* cmd)
281 {
282     fprintf(CurrentClient, "Swapped In Memory\t0\t0\tKB/s\n");
283 }
284 
printSwapOut(const char * cmd)285 void printSwapOut(const char* cmd)
286 {
287     fprintf(CurrentClient, "%lu\n", swap_stats[SWAP_OUT]);
288 }
289 
printSwapOutInfo(const char * cmd)290 void printSwapOutInfo(const char* cmd)
291 {
292     fprintf(CurrentClient, "Swapped Out Memory\t0\t0\tKB/s\n");
293 }
294 
295 /* Adapted from src/lib/libkvm/kvm_getswapinfo.c */
296 #define SWI_MAXMIB 3
297 
kvm_getswapinfo_sysctl(size_t * ksw_used,size_t * ksw_total)298 void kvm_getswapinfo_sysctl(size_t *ksw_used, size_t *ksw_total)
299 {
300     int unswdev;
301     size_t len;
302     static int soid[SWI_MAXMIB], dmmax = -1;
303     static size_t mibi = -1;
304     struct xswdev xsd;
305 
306     *ksw_used = 0;
307     *ksw_total = 0;
308     if (dmmax == -1) {
309         len = sizeof(dmmax);
310         if (sysctlbyname("vm.dmmax", &dmmax, &len, NULL, 0) || len != sizeof(dmmax)) {
311             dmmax = -1;
312             return;
313         }
314     }
315 
316     if (mibi == -1) {
317         mibi = SWI_MAXMIB - 1;
318         if (sysctlnametomib("vm.swap_info", soid, &mibi) == -1) {
319             mibi = -1;
320             return;
321         }
322     }
323 
324     for (unswdev = 0;; unswdev++) {
325         soid[mibi] = unswdev;
326         len = sizeof(xsd);
327         if (sysctl(soid, mibi + 1, &xsd, &len, NULL, 0) || len != sizeof(xsd)) {
328             return;
329         }
330 
331         *ksw_used += xsd.xsw_used;
332         *ksw_total += xsd.xsw_nblks - dmmax;
333     }
334 }
335