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