1 |
|
|
/* $NetBSD: vmstat.c,v 1.29.4.1 1996/06/05 00:21:05 cgd Exp $ */ |
2 |
|
|
/* $OpenBSD: vmstat.c,v 1.139 2015/12/24 03:25:08 mmcc Exp $ */ |
3 |
|
|
|
4 |
|
|
/* |
5 |
|
|
* Copyright (c) 1980, 1986, 1991, 1993 |
6 |
|
|
* The Regents of the University of California. All rights reserved. |
7 |
|
|
* |
8 |
|
|
* Redistribution and use in source and binary forms, with or without |
9 |
|
|
* modification, are permitted provided that the following conditions |
10 |
|
|
* are met: |
11 |
|
|
* 1. Redistributions of source code must retain the above copyright |
12 |
|
|
* notice, this list of conditions and the following disclaimer. |
13 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
14 |
|
|
* notice, this list of conditions and the following disclaimer in the |
15 |
|
|
* documentation and/or other materials provided with the distribution. |
16 |
|
|
* 3. Neither the name of the University nor the names of its contributors |
17 |
|
|
* may be used to endorse or promote products derived from this software |
18 |
|
|
* without specific prior written permission. |
19 |
|
|
* |
20 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
21 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
22 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
23 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
24 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
25 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
26 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
27 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
28 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
29 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
30 |
|
|
* SUCH DAMAGE. |
31 |
|
|
*/ |
32 |
|
|
|
33 |
|
|
#include <sys/param.h> /* MAXCOMLEN */ |
34 |
|
|
#include <sys/time.h> |
35 |
|
|
#include <sys/proc.h> |
36 |
|
|
#include <sys/namei.h> |
37 |
|
|
#include <sys/malloc.h> |
38 |
|
|
#include <sys/fcntl.h> |
39 |
|
|
#include <sys/ioctl.h> |
40 |
|
|
#include <sys/sysctl.h> |
41 |
|
|
#include <sys/device.h> |
42 |
|
|
#include <sys/pool.h> |
43 |
|
|
#include <sys/sched.h> |
44 |
|
|
#include <sys/vmmeter.h> |
45 |
|
|
|
46 |
|
|
#include <time.h> |
47 |
|
|
#include <nlist.h> |
48 |
|
|
#include <kvm.h> |
49 |
|
|
#include <err.h> |
50 |
|
|
#include <errno.h> |
51 |
|
|
#include <unistd.h> |
52 |
|
|
#include <signal.h> |
53 |
|
|
#include <stdio.h> |
54 |
|
|
#include <ctype.h> |
55 |
|
|
#include <stdlib.h> |
56 |
|
|
#include <string.h> |
57 |
|
|
#include <paths.h> |
58 |
|
|
#include <limits.h> |
59 |
|
|
#include "dkstats.h" |
60 |
|
|
|
61 |
|
|
struct nlist namelist[] = { |
62 |
|
|
#define X_UVMEXP 0 /* sysctl */ |
63 |
|
|
{ "_uvmexp" }, |
64 |
|
|
#define X_TIME_UPTIME 1 |
65 |
|
|
{ "_time_uptime" }, |
66 |
|
|
#define X_NCHSTATS 2 /* sysctl */ |
67 |
|
|
{ "_nchstats" }, |
68 |
|
|
#define X_KMEMSTAT 3 /* sysctl */ |
69 |
|
|
{ "_kmemstats" }, |
70 |
|
|
#define X_KMEMBUCKETS 4 /* sysctl */ |
71 |
|
|
{ "_bucket" }, |
72 |
|
|
#define X_FORKSTAT 5 /* sysctl */ |
73 |
|
|
{ "_forkstat" }, |
74 |
|
|
#define X_NSELCOLL 6 /* sysctl */ |
75 |
|
|
{ "_nselcoll" }, |
76 |
|
|
#define X_POOLHEAD 7 /* sysctl */ |
77 |
|
|
{ "_pool_head" }, |
78 |
|
|
#define X_NAPTIME 8 |
79 |
|
|
{ "_naptime" }, |
80 |
|
|
{ "" }, |
81 |
|
|
}; |
82 |
|
|
|
83 |
|
|
/* Objects defined in dkstats.c */ |
84 |
|
|
extern struct _disk cur, last; |
85 |
|
|
extern char **dr_name; |
86 |
|
|
extern int *dk_select, dk_ndrive; |
87 |
|
|
|
88 |
|
|
struct uvmexp uvmexp, ouvmexp; |
89 |
|
|
int ndrives; |
90 |
|
|
|
91 |
|
|
int winlines = 20; |
92 |
|
|
|
93 |
|
|
kvm_t *kd; |
94 |
|
|
|
95 |
|
|
#define FORKSTAT 0x01 |
96 |
|
|
#define INTRSTAT 0x02 |
97 |
|
|
#define MEMSTAT 0x04 |
98 |
|
|
#define SUMSTAT 0x08 |
99 |
|
|
#define TIMESTAT 0x10 |
100 |
|
|
#define VMSTAT 0x20 |
101 |
|
|
|
102 |
|
|
void cpustats(void); |
103 |
|
|
time_t getuptime(void); |
104 |
|
|
void dkstats(void); |
105 |
|
|
void dointr(void); |
106 |
|
|
void domem(void); |
107 |
|
|
void dopool(void); |
108 |
|
|
void dosum(void); |
109 |
|
|
void dovmstat(u_int, int); |
110 |
|
|
void kread(int, void *, size_t); |
111 |
|
|
void usage(void); |
112 |
|
|
void dotimes(void); |
113 |
|
|
void doforkst(void); |
114 |
|
|
void needhdr(int); |
115 |
|
|
int pct(int64_t, int64_t); |
116 |
|
|
void printhdr(void); |
117 |
|
|
|
118 |
|
|
char **choosedrives(char **); |
119 |
|
|
|
120 |
|
|
/* Namelist and memory file names. */ |
121 |
|
|
char *nlistf, *memf; |
122 |
|
|
|
123 |
|
|
extern char *__progname; |
124 |
|
|
|
125 |
|
|
int verbose = 0; |
126 |
|
|
int zflag = 0; |
127 |
|
|
|
128 |
|
|
int |
129 |
|
|
main(int argc, char *argv[]) |
130 |
|
|
{ |
131 |
|
|
char errbuf[_POSIX2_LINE_MAX]; |
132 |
|
|
int c, todo = 0, reps = 0; |
133 |
|
|
const char *errstr; |
134 |
|
|
u_int interval = 0; |
135 |
|
|
|
136 |
|
|
while ((c = getopt(argc, argv, "c:fiM:mN:stw:vz")) != -1) { |
137 |
|
|
switch (c) { |
138 |
|
|
case 'c': |
139 |
|
|
reps = strtonum(optarg, 0, INT_MAX, &errstr); |
140 |
|
|
if (errstr) |
141 |
|
|
errx(1, "-c %s: %s", optarg, errstr); |
142 |
|
|
break; |
143 |
|
|
case 'f': |
144 |
|
|
todo |= FORKSTAT; |
145 |
|
|
break; |
146 |
|
|
case 'i': |
147 |
|
|
todo |= INTRSTAT; |
148 |
|
|
break; |
149 |
|
|
case 'M': |
150 |
|
|
memf = optarg; |
151 |
|
|
break; |
152 |
|
|
case 'm': |
153 |
|
|
todo |= MEMSTAT; |
154 |
|
|
break; |
155 |
|
|
case 'N': |
156 |
|
|
nlistf = optarg; |
157 |
|
|
break; |
158 |
|
|
case 's': |
159 |
|
|
todo |= SUMSTAT; |
160 |
|
|
break; |
161 |
|
|
case 't': |
162 |
|
|
todo |= TIMESTAT; |
163 |
|
|
break; |
164 |
|
|
case 'w': |
165 |
|
|
interval = (u_int)strtonum(optarg, 0, 1000, &errstr); |
166 |
|
|
if (errstr) |
167 |
|
|
errx(1, "-w %s: %s", optarg, errstr); |
168 |
|
|
break; |
169 |
|
|
case 'v': |
170 |
|
|
verbose = 1; |
171 |
|
|
break; |
172 |
|
|
case 'z': |
173 |
|
|
zflag = 1; |
174 |
|
|
break; |
175 |
|
|
case '?': |
176 |
|
|
default: |
177 |
|
|
usage(); |
178 |
|
|
} |
179 |
|
|
} |
180 |
|
|
argc -= optind; |
181 |
|
|
argv += optind; |
182 |
|
|
|
183 |
|
|
if (todo == 0) |
184 |
|
|
todo = VMSTAT; |
185 |
|
|
|
186 |
|
|
if (nlistf != NULL || memf != NULL) { |
187 |
|
|
|
188 |
|
|
kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); |
189 |
|
|
if (kd == 0) |
190 |
|
|
errx(1, "kvm_openfiles: %s", errbuf); |
191 |
|
|
|
192 |
|
|
if ((c = kvm_nlist(kd, namelist)) != 0) { |
193 |
|
|
|
194 |
|
|
if (c > 0) { |
195 |
|
|
(void)fprintf(stderr, |
196 |
|
|
"%s: undefined symbols:", __progname); |
197 |
|
|
for (c = 0; |
198 |
|
|
c < sizeof(namelist)/sizeof(namelist[0]); |
199 |
|
|
c++) |
200 |
|
|
if (namelist[c].n_type == 0) |
201 |
|
|
fprintf(stderr, " %s", |
202 |
|
|
namelist[c].n_name); |
203 |
|
|
(void)fputc('\n', stderr); |
204 |
|
|
exit(1); |
205 |
|
|
} else |
206 |
|
|
errx(1, "kvm_nlist: %s", kvm_geterr(kd)); |
207 |
|
|
} |
208 |
|
|
} |
209 |
|
|
|
210 |
|
|
if (todo & VMSTAT) { |
211 |
|
|
struct winsize winsize; |
212 |
|
|
|
213 |
|
|
dkinit(0); /* Initialize disk stats, no disks selected. */ |
214 |
|
|
argv = choosedrives(argv); /* Select disks. */ |
215 |
|
|
winsize.ws_row = 0; |
216 |
|
|
(void) ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize); |
217 |
|
|
if (winsize.ws_row > 0) |
218 |
|
|
winlines = winsize.ws_row; |
219 |
|
|
|
220 |
|
|
} |
221 |
|
|
|
222 |
|
|
#define BACKWARD_COMPATIBILITY |
223 |
|
|
#ifdef BACKWARD_COMPATIBILITY |
224 |
|
|
if (*argv) { |
225 |
|
|
interval = (u_int)strtonum(*argv, 0, 1000, &errstr); |
226 |
|
|
if (errstr) |
227 |
|
|
errx(1, "interval %s: %s", *argv, errstr); |
228 |
|
|
|
229 |
|
|
if (*++argv) { |
230 |
|
|
reps = strtonum(*argv, 0, INT_MAX, &errstr); |
231 |
|
|
if (errstr) |
232 |
|
|
errx(1, "reps %s: %s", *argv, errstr); |
233 |
|
|
} |
234 |
|
|
} |
235 |
|
|
#endif |
236 |
|
|
|
237 |
|
|
if (interval) { |
238 |
|
|
if (!reps) |
239 |
|
|
reps = -1; |
240 |
|
|
} else if (reps) |
241 |
|
|
interval = 1; |
242 |
|
|
|
243 |
|
|
if (todo & FORKSTAT) |
244 |
|
|
doforkst(); |
245 |
|
|
if (todo & MEMSTAT) { |
246 |
|
|
domem(); |
247 |
|
|
dopool(); |
248 |
|
|
} |
249 |
|
|
if (todo & SUMSTAT) |
250 |
|
|
dosum(); |
251 |
|
|
if (todo & TIMESTAT) |
252 |
|
|
dotimes(); |
253 |
|
|
if (todo & INTRSTAT) |
254 |
|
|
dointr(); |
255 |
|
|
if (todo & VMSTAT) |
256 |
|
|
dovmstat(interval, reps); |
257 |
|
|
exit(0); |
258 |
|
|
} |
259 |
|
|
|
260 |
|
|
char ** |
261 |
|
|
choosedrives(char **argv) |
262 |
|
|
{ |
263 |
|
|
int i; |
264 |
|
|
|
265 |
|
|
/* |
266 |
|
|
* Choose drives to be displayed. Priority goes to (in order) drives |
267 |
|
|
* supplied as arguments, default drives. If everything isn't filled |
268 |
|
|
* in and there are drives not taken care of, display the first few |
269 |
|
|
* that fit. |
270 |
|
|
*/ |
271 |
|
|
#define BACKWARD_COMPATIBILITY |
272 |
|
|
for (ndrives = 0; *argv; ++argv) { |
273 |
|
|
#ifdef BACKWARD_COMPATIBILITY |
274 |
|
|
if (isdigit((unsigned char)**argv)) |
275 |
|
|
break; |
276 |
|
|
#endif |
277 |
|
|
for (i = 0; i < dk_ndrive; i++) { |
278 |
|
|
if (strcmp(dr_name[i], *argv)) |
279 |
|
|
continue; |
280 |
|
|
dk_select[i] = 1; |
281 |
|
|
++ndrives; |
282 |
|
|
break; |
283 |
|
|
} |
284 |
|
|
if (i == dk_ndrive) |
285 |
|
|
errx(1, "invalid interval or drive name: %s", *argv); |
286 |
|
|
} |
287 |
|
|
for (i = 0; i < dk_ndrive && ndrives < 2; i++) { |
288 |
|
|
if (dk_select[i]) |
289 |
|
|
continue; |
290 |
|
|
dk_select[i] = 1; |
291 |
|
|
++ndrives; |
292 |
|
|
} |
293 |
|
|
return(argv); |
294 |
|
|
} |
295 |
|
|
|
296 |
|
|
time_t |
297 |
|
|
getuptime(void) |
298 |
|
|
{ |
299 |
|
|
struct timespec uptime; |
300 |
|
|
time_t time_uptime, naptime; |
301 |
|
|
|
302 |
|
|
if (nlistf == NULL && memf == NULL) { |
303 |
|
|
if (clock_gettime(CLOCK_UPTIME, &uptime) == -1) |
304 |
|
|
err(1, "clock_gettime"); |
305 |
|
|
return (uptime.tv_sec); |
306 |
|
|
} |
307 |
|
|
|
308 |
|
|
kread(X_NAPTIME, &naptime, sizeof(naptime)); |
309 |
|
|
kread(X_TIME_UPTIME, &time_uptime, sizeof(time_uptime)); |
310 |
|
|
return (time_uptime - naptime); |
311 |
|
|
} |
312 |
|
|
|
313 |
|
|
int hz; |
314 |
|
|
volatile sig_atomic_t hdrcnt; |
315 |
|
|
|
316 |
|
|
void |
317 |
|
|
dovmstat(u_int interval, int reps) |
318 |
|
|
{ |
319 |
|
|
time_t uptime, halfuptime; |
320 |
|
|
struct clockinfo clkinfo; |
321 |
|
|
struct vmtotal total; |
322 |
|
|
size_t size; |
323 |
|
|
int mib[2]; |
324 |
|
|
|
325 |
|
|
uptime = getuptime(); |
326 |
|
|
halfuptime = uptime / 2; |
327 |
|
|
(void)signal(SIGCONT, needhdr); |
328 |
|
|
|
329 |
|
|
mib[0] = CTL_KERN; |
330 |
|
|
mib[1] = KERN_CLOCKRATE; |
331 |
|
|
size = sizeof(clkinfo); |
332 |
|
|
if (sysctl(mib, 2, &clkinfo, &size, NULL, 0) < 0) { |
333 |
|
|
warn("could not read kern.clockrate"); |
334 |
|
|
return; |
335 |
|
|
} |
336 |
|
|
hz = clkinfo.stathz; |
337 |
|
|
|
338 |
|
|
for (hdrcnt = 1;;) { |
339 |
|
|
/* Read new disk statistics */ |
340 |
|
|
dkreadstats(); |
341 |
|
|
if (!--hdrcnt || last.dk_ndrive != cur.dk_ndrive) |
342 |
|
|
printhdr(); |
343 |
|
|
if (nlistf == NULL && memf == NULL) { |
344 |
|
|
size = sizeof(struct uvmexp); |
345 |
|
|
mib[0] = CTL_VM; |
346 |
|
|
mib[1] = VM_UVMEXP; |
347 |
|
|
if (sysctl(mib, 2, &uvmexp, &size, NULL, 0) < 0) { |
348 |
|
|
warn("could not get vm.uvmexp"); |
349 |
|
|
memset(&uvmexp, 0, sizeof(struct uvmexp)); |
350 |
|
|
} |
351 |
|
|
} else { |
352 |
|
|
kread(X_UVMEXP, &uvmexp, sizeof(struct uvmexp)); |
353 |
|
|
} |
354 |
|
|
size = sizeof(total); |
355 |
|
|
mib[0] = CTL_VM; |
356 |
|
|
mib[1] = VM_METER; |
357 |
|
|
if (sysctl(mib, 2, &total, &size, NULL, 0) < 0) { |
358 |
|
|
warn("could not read vm.vmmeter"); |
359 |
|
|
memset(&total, 0, sizeof(total)); |
360 |
|
|
} |
361 |
|
|
(void)printf(" %u %u %u ", |
362 |
|
|
total.t_rq - 1, total.t_dw + total.t_pw, total.t_sw); |
363 |
|
|
#define rate(x) ((unsigned)((((unsigned)x) + halfuptime) / uptime)) /* round */ |
364 |
|
|
#define pgtok(a) ((a) * ((unsigned int)uvmexp.pagesize >> 10)) |
365 |
|
|
(void)printf("%6u %7u ", |
366 |
|
|
pgtok(uvmexp.active + uvmexp.swpginuse), |
367 |
|
|
pgtok(uvmexp.free)); |
368 |
|
|
(void)printf("%4u ", rate(uvmexp.faults - ouvmexp.faults)); |
369 |
|
|
(void)printf("%3u ", rate(uvmexp.pdreact - ouvmexp.pdreact)); |
370 |
|
|
(void)printf("%3u ", rate(uvmexp.pageins - ouvmexp.pageins)); |
371 |
|
|
(void)printf("%3u %3u ", |
372 |
|
|
rate(uvmexp.pdpageouts - ouvmexp.pdpageouts), 0); |
373 |
|
|
(void)printf("%3u ", rate(uvmexp.pdscans - ouvmexp.pdscans)); |
374 |
|
|
dkstats(); |
375 |
|
|
(void)printf("%4u %5u %4u ", |
376 |
|
|
rate(uvmexp.intrs - ouvmexp.intrs), |
377 |
|
|
rate(uvmexp.syscalls - ouvmexp.syscalls), |
378 |
|
|
rate(uvmexp.swtch - ouvmexp.swtch)); |
379 |
|
|
cpustats(); |
380 |
|
|
(void)printf("\n"); |
381 |
|
|
(void)fflush(stdout); |
382 |
|
|
if (reps >= 0 && --reps <= 0) |
383 |
|
|
break; |
384 |
|
|
ouvmexp = uvmexp; |
385 |
|
|
uptime = interval; |
386 |
|
|
/* |
387 |
|
|
* We round upward to avoid losing low-frequency events |
388 |
|
|
* (i.e., >= 1 per interval but < 1 per second). |
389 |
|
|
*/ |
390 |
|
|
halfuptime = uptime == 1 ? 0 : (uptime + 1) / 2; |
391 |
|
|
(void)sleep(interval); |
392 |
|
|
} |
393 |
|
|
} |
394 |
|
|
|
395 |
|
|
void |
396 |
|
|
printhdr(void) |
397 |
|
|
{ |
398 |
|
|
int i; |
399 |
|
|
static int printedhdr; |
400 |
|
|
|
401 |
|
|
if (printedhdr && !isatty(STDOUT_FILENO)) |
402 |
|
|
return; |
403 |
|
|
|
404 |
|
|
(void)printf(" procs memory page%*s", 20, ""); |
405 |
|
|
if (ndrives > 0) |
406 |
|
|
(void)printf("%s %*straps cpu\n", |
407 |
|
|
((ndrives > 1) ? "disks" : "disk"), |
408 |
|
|
((ndrives > 1) ? ndrives * 4 - 5 : 0), ""); |
409 |
|
|
else |
410 |
|
|
(void)printf("%*s traps cpu\n", |
411 |
|
|
ndrives * 3, ""); |
412 |
|
|
|
413 |
|
|
(void)printf(" r b w avm fre flt re pi po fr sr "); |
414 |
|
|
for (i = 0; i < dk_ndrive; i++) |
415 |
|
|
if (dk_select[i]) |
416 |
|
|
(void)printf("%c%c%c ", dr_name[i][0], |
417 |
|
|
dr_name[i][1], |
418 |
|
|
dr_name[i][strlen(dr_name[i]) - 1]); |
419 |
|
|
(void)printf(" int sys cs us sy id\n"); |
420 |
|
|
hdrcnt = winlines - 2; |
421 |
|
|
printedhdr = 1; |
422 |
|
|
} |
423 |
|
|
|
424 |
|
|
/* |
425 |
|
|
* Force a header to be prepended to the next output. |
426 |
|
|
*/ |
427 |
|
|
/* ARGSUSED */ |
428 |
|
|
void |
429 |
|
|
needhdr(int signo) |
430 |
|
|
{ |
431 |
|
|
|
432 |
|
|
hdrcnt = 1; |
433 |
|
|
} |
434 |
|
|
|
435 |
|
|
void |
436 |
|
|
dotimes(void) |
437 |
|
|
{ |
438 |
|
|
u_int pgintime, rectime; |
439 |
|
|
size_t size; |
440 |
|
|
int mib[2]; |
441 |
|
|
|
442 |
|
|
/* XXX Why are these set to 0 ? This doesn't look right. */ |
443 |
|
|
pgintime = 0; |
444 |
|
|
rectime = 0; |
445 |
|
|
|
446 |
|
|
if (nlistf == NULL && memf == NULL) { |
447 |
|
|
size = sizeof(struct uvmexp); |
448 |
|
|
mib[0] = CTL_VM; |
449 |
|
|
mib[1] = VM_UVMEXP; |
450 |
|
|
if (sysctl(mib, 2, &uvmexp, &size, NULL, 0) < 0) { |
451 |
|
|
warn("could not read vm.uvmexp"); |
452 |
|
|
memset(&uvmexp, 0, sizeof(struct uvmexp)); |
453 |
|
|
} |
454 |
|
|
} else { |
455 |
|
|
kread(X_UVMEXP, &uvmexp, sizeof(struct uvmexp)); |
456 |
|
|
} |
457 |
|
|
|
458 |
|
|
(void)printf("%u reactivates, %u total time (usec)\n", |
459 |
|
|
uvmexp.pdreact, rectime); |
460 |
|
|
if (uvmexp.pdreact != 0) |
461 |
|
|
(void)printf("average: %u usec / reclaim\n", |
462 |
|
|
rectime / uvmexp.pdreact); |
463 |
|
|
(void)printf("\n"); |
464 |
|
|
(void)printf("%u page ins, %u total time (msec)\n", |
465 |
|
|
uvmexp.pageins, pgintime / 10); |
466 |
|
|
if (uvmexp.pageins != 0) |
467 |
|
|
(void)printf("average: %8.1f msec / page in\n", |
468 |
|
|
pgintime / (uvmexp.pageins * 10.0)); |
469 |
|
|
} |
470 |
|
|
|
471 |
|
|
int |
472 |
|
|
pct(int64_t top, int64_t bot) |
473 |
|
|
{ |
474 |
|
|
int ans; |
475 |
|
|
|
476 |
|
|
if (bot == 0) |
477 |
|
|
return(0); |
478 |
|
|
ans = top * 100 / bot; |
479 |
|
|
return (ans); |
480 |
|
|
} |
481 |
|
|
|
482 |
|
|
void |
483 |
|
|
dosum(void) |
484 |
|
|
{ |
485 |
|
|
struct nchstats nchstats; |
486 |
|
|
int mib[2], nselcoll; |
487 |
|
|
long long nchtotal; |
488 |
|
|
size_t size; |
489 |
|
|
|
490 |
|
|
if (nlistf == NULL && memf == NULL) { |
491 |
|
|
size = sizeof(struct uvmexp); |
492 |
|
|
mib[0] = CTL_VM; |
493 |
|
|
mib[1] = VM_UVMEXP; |
494 |
|
|
if (sysctl(mib, 2, &uvmexp, &size, NULL, 0) < 0) { |
495 |
|
|
warn("could not read vm.uvmexp"); |
496 |
|
|
memset(&uvmexp, 0, sizeof(struct uvmexp)); |
497 |
|
|
} |
498 |
|
|
} else { |
499 |
|
|
kread(X_UVMEXP, &uvmexp, sizeof(struct uvmexp)); |
500 |
|
|
} |
501 |
|
|
|
502 |
|
|
/* vm_page constants */ |
503 |
|
|
(void)printf("%11u bytes per page\n", uvmexp.pagesize); |
504 |
|
|
|
505 |
|
|
/* vm_page counters */ |
506 |
|
|
(void)printf("%11u pages managed\n", uvmexp.npages); |
507 |
|
|
(void)printf("%11u pages free\n", uvmexp.free); |
508 |
|
|
(void)printf("%11u pages active\n", uvmexp.active); |
509 |
|
|
(void)printf("%11u pages inactive\n", uvmexp.inactive); |
510 |
|
|
(void)printf("%11u pages being paged out\n", uvmexp.paging); |
511 |
|
|
(void)printf("%11u pages wired\n", uvmexp.wired); |
512 |
|
|
(void)printf("%11u pages zeroed\n", uvmexp.zeropages); |
513 |
|
|
(void)printf("%11u pages reserved for pagedaemon\n", |
514 |
|
|
uvmexp.reserve_pagedaemon); |
515 |
|
|
(void)printf("%11u pages reserved for kernel\n", |
516 |
|
|
uvmexp.reserve_kernel); |
517 |
|
|
|
518 |
|
|
/* swap */ |
519 |
|
|
(void)printf("%11u swap pages\n", uvmexp.swpages); |
520 |
|
|
(void)printf("%11u swap pages in use\n", uvmexp.swpginuse); |
521 |
|
|
(void)printf("%11u total anon's in system\n", uvmexp.nanon); |
522 |
|
|
(void)printf("%11u free anon's\n", uvmexp.nfreeanon); |
523 |
|
|
|
524 |
|
|
/* stat counters */ |
525 |
|
|
(void)printf("%11u page faults\n", uvmexp.faults); |
526 |
|
|
(void)printf("%11u traps\n", uvmexp.traps); |
527 |
|
|
(void)printf("%11u interrupts\n", uvmexp.intrs); |
528 |
|
|
(void)printf("%11u cpu context switches\n", uvmexp.swtch); |
529 |
|
|
(void)printf("%11u fpu context switches\n", uvmexp.fpswtch); |
530 |
|
|
(void)printf("%11u software interrupts\n", uvmexp.softs); |
531 |
|
|
(void)printf("%11u syscalls\n", uvmexp.syscalls); |
532 |
|
|
(void)printf("%11u pagein operations\n", uvmexp.pageins); |
533 |
|
|
(void)printf("%11u forks\n", uvmexp.forks); |
534 |
|
|
(void)printf("%11u forks where vmspace is shared\n", |
535 |
|
|
uvmexp.forks_sharevm); |
536 |
|
|
(void)printf("%11u kernel map entries\n", uvmexp.kmapent); |
537 |
|
|
(void)printf("%11u zeroed page hits\n", uvmexp.pga_zerohit); |
538 |
|
|
(void)printf("%11u zeroed page misses\n", uvmexp.pga_zeromiss); |
539 |
|
|
|
540 |
|
|
/* daemon counters */ |
541 |
|
|
(void)printf("%11u number of times the pagedaemon woke up\n", |
542 |
|
|
uvmexp.pdwoke); |
543 |
|
|
(void)printf("%11u revolutions of the clock hand\n", uvmexp.pdrevs); |
544 |
|
|
(void)printf("%11u pages freed by pagedaemon\n", uvmexp.pdfreed); |
545 |
|
|
(void)printf("%11u pages scanned by pagedaemon\n", uvmexp.pdscans); |
546 |
|
|
(void)printf("%11u pages reactivated by pagedaemon\n", uvmexp.pdreact); |
547 |
|
|
(void)printf("%11u busy pages found by pagedaemon\n", uvmexp.pdbusy); |
548 |
|
|
|
549 |
|
|
if (nlistf == NULL && memf == NULL) { |
550 |
|
|
size = sizeof(nchstats); |
551 |
|
|
mib[0] = CTL_KERN; |
552 |
|
|
mib[1] = KERN_NCHSTATS; |
553 |
|
|
if (sysctl(mib, 2, &nchstats, &size, NULL, 0) < 0) { |
554 |
|
|
warn("could not read kern.nchstats"); |
555 |
|
|
memset(&nchstats, 0, sizeof(nchstats)); |
556 |
|
|
} |
557 |
|
|
} else { |
558 |
|
|
kread(X_NCHSTATS, &nchstats, sizeof(nchstats)); |
559 |
|
|
} |
560 |
|
|
|
561 |
|
|
nchtotal = nchstats.ncs_goodhits + nchstats.ncs_neghits + |
562 |
|
|
nchstats.ncs_badhits + nchstats.ncs_falsehits + |
563 |
|
|
nchstats.ncs_miss + nchstats.ncs_long; |
564 |
|
|
(void)printf("%11lld total name lookups\n", nchtotal); |
565 |
|
|
(void)printf("%11s cache hits (%d%% pos + %d%% neg) system %d%% " |
566 |
|
|
"per-directory\n", |
567 |
|
|
"", pct(nchstats.ncs_goodhits, nchtotal), |
568 |
|
|
pct(nchstats.ncs_neghits, nchtotal), |
569 |
|
|
pct(nchstats.ncs_pass2, nchtotal)); |
570 |
|
|
(void)printf("%11s deletions %d%%, falsehits %d%%, toolong %d%%\n", "", |
571 |
|
|
pct(nchstats.ncs_badhits, nchtotal), |
572 |
|
|
pct(nchstats.ncs_falsehits, nchtotal), |
573 |
|
|
pct(nchstats.ncs_long, nchtotal)); |
574 |
|
|
|
575 |
|
|
if (nlistf == NULL && memf == NULL) { |
576 |
|
|
size = sizeof(nselcoll); |
577 |
|
|
mib[0] = CTL_KERN; |
578 |
|
|
mib[1] = KERN_NSELCOLL; |
579 |
|
|
if (sysctl(mib, 2, &nselcoll, &size, NULL, 0) < 0) { |
580 |
|
|
warn("could not read kern.nselcoll"); |
581 |
|
|
nselcoll = 0; |
582 |
|
|
} |
583 |
|
|
} else { |
584 |
|
|
kread(X_NSELCOLL, &nselcoll, sizeof(nselcoll)); |
585 |
|
|
} |
586 |
|
|
(void)printf("%11d select collisions\n", nselcoll); |
587 |
|
|
} |
588 |
|
|
|
589 |
|
|
void |
590 |
|
|
doforkst(void) |
591 |
|
|
{ |
592 |
|
|
struct forkstat fks; |
593 |
|
|
size_t size; |
594 |
|
|
int mib[2]; |
595 |
|
|
|
596 |
|
|
if (nlistf == NULL && memf == NULL) { |
597 |
|
|
size = sizeof(struct forkstat); |
598 |
|
|
mib[0] = CTL_KERN; |
599 |
|
|
mib[1] = KERN_FORKSTAT; |
600 |
|
|
if (sysctl(mib, 2, &fks, &size, NULL, 0) < 0) { |
601 |
|
|
warn("could not read kern.forkstat"); |
602 |
|
|
memset(&fks, 0, sizeof(struct forkstat)); |
603 |
|
|
} |
604 |
|
|
} else { |
605 |
|
|
kread(X_FORKSTAT, &fks, sizeof(struct forkstat)); |
606 |
|
|
} |
607 |
|
|
|
608 |
|
|
(void)printf("%d forks, %d pages, average %.2f\n", |
609 |
|
|
fks.cntfork, fks.sizfork, (double)fks.sizfork / fks.cntfork); |
610 |
|
|
(void)printf("%d vforks, %d pages, average %.2f\n", |
611 |
|
|
fks.cntvfork, fks.sizvfork, |
612 |
|
|
(double)fks.sizvfork / (fks.cntvfork ? fks.cntvfork : 1)); |
613 |
|
|
(void)printf("%d __tforks, %d pages, average %.2f\n", |
614 |
|
|
fks.cnttfork, fks.siztfork, |
615 |
|
|
(double)fks.siztfork / (fks.cnttfork ? fks.cnttfork : 1)); |
616 |
|
|
(void)printf("%d kthread creations, %d pages, average %.2f\n", |
617 |
|
|
fks.cntkthread, fks.sizkthread, |
618 |
|
|
(double)fks.sizkthread / (fks.cntkthread ? fks.cntkthread : 1)); |
619 |
|
|
} |
620 |
|
|
|
621 |
|
|
void |
622 |
|
|
dkstats(void) |
623 |
|
|
{ |
624 |
|
|
int dn, state; |
625 |
|
|
double etime; |
626 |
|
|
|
627 |
|
|
/* Calculate disk stat deltas. */ |
628 |
|
|
dkswap(); |
629 |
|
|
etime = 0; |
630 |
|
|
for (state = 0; state < CPUSTATES; ++state) { |
631 |
|
|
etime += cur.cp_time[state]; |
632 |
|
|
} |
633 |
|
|
if (etime == 0) |
634 |
|
|
etime = 1; |
635 |
|
|
etime /= hz; |
636 |
|
|
for (dn = 0; dn < dk_ndrive; ++dn) { |
637 |
|
|
if (!dk_select[dn]) |
638 |
|
|
continue; |
639 |
|
|
(void)printf("%3.0f ", |
640 |
|
|
(cur.dk_rxfer[dn] + cur.dk_rxfer[dn]) / etime); |
641 |
|
|
} |
642 |
|
|
} |
643 |
|
|
|
644 |
|
|
void |
645 |
|
|
cpustats(void) |
646 |
|
|
{ |
647 |
|
|
double percent, total; |
648 |
|
|
int state; |
649 |
|
|
|
650 |
|
|
total = 0; |
651 |
|
|
for (state = 0; state < CPUSTATES; ++state) |
652 |
|
|
total += cur.cp_time[state]; |
653 |
|
|
if (total) |
654 |
|
|
percent = 100 / total; |
655 |
|
|
else |
656 |
|
|
percent = 0; |
657 |
|
|
(void)printf("%2.0f ", (cur.cp_time[CP_USER] + cur.cp_time[CP_NICE]) * percent); |
658 |
|
|
(void)printf("%2.0f ", (cur.cp_time[CP_SYS] + cur.cp_time[CP_INTR]) * percent); |
659 |
|
|
(void)printf("%2.0f", cur.cp_time[CP_IDLE] * percent); |
660 |
|
|
} |
661 |
|
|
|
662 |
|
|
void |
663 |
|
|
dointr(void) |
664 |
|
|
{ |
665 |
|
|
int nintr, mib[4], i; |
666 |
|
|
char intrname[128]; |
667 |
|
|
u_int64_t inttotal; |
668 |
|
|
time_t uptime; |
669 |
|
|
size_t siz; |
670 |
|
|
|
671 |
|
|
if (nlistf != NULL || memf != NULL) { |
672 |
|
|
errx(1, |
673 |
|
|
"interrupt statistics are only available on live kernels"); |
674 |
|
|
} |
675 |
|
|
|
676 |
|
|
uptime = getuptime(); |
677 |
|
|
|
678 |
|
|
mib[0] = CTL_KERN; |
679 |
|
|
mib[1] = KERN_INTRCNT; |
680 |
|
|
mib[2] = KERN_INTRCNT_NUM; |
681 |
|
|
siz = sizeof(nintr); |
682 |
|
|
if (sysctl(mib, 3, &nintr, &siz, NULL, 0) < 0) { |
683 |
|
|
warnx("could not read kern.intrcnt.nintrcnt"); |
684 |
|
|
return; |
685 |
|
|
} |
686 |
|
|
|
687 |
|
|
(void)printf("%-16s %20s %8s\n", "interrupt", "total", "rate"); |
688 |
|
|
|
689 |
|
|
inttotal = 0; |
690 |
|
|
for (i = 0; i < nintr; i++) { |
691 |
|
|
char name[128]; |
692 |
|
|
u_quad_t cnt; |
693 |
|
|
int vector; |
694 |
|
|
|
695 |
|
|
mib[0] = CTL_KERN; |
696 |
|
|
mib[1] = KERN_INTRCNT; |
697 |
|
|
mib[2] = KERN_INTRCNT_NAME; |
698 |
|
|
mib[3] = i; |
699 |
|
|
siz = sizeof(name); |
700 |
|
|
if (sysctl(mib, 4, name, &siz, NULL, 0) < 0) { |
701 |
|
|
warnx("could not read kern.intrcnt.name.%d", i); |
702 |
|
|
return; |
703 |
|
|
} |
704 |
|
|
|
705 |
|
|
mib[0] = CTL_KERN; |
706 |
|
|
mib[1] = KERN_INTRCNT; |
707 |
|
|
mib[2] = KERN_INTRCNT_VECTOR; |
708 |
|
|
mib[3] = i; |
709 |
|
|
siz = sizeof(vector); |
710 |
|
|
if (sysctl(mib, 4, &vector, &siz, NULL, 0) < 0) { |
711 |
|
|
strlcpy(intrname, name, sizeof(intrname)); |
712 |
|
|
} else { |
713 |
|
|
snprintf(intrname, sizeof(intrname), "irq%d/%s", |
714 |
|
|
vector, name); |
715 |
|
|
} |
716 |
|
|
|
717 |
|
|
mib[0] = CTL_KERN; |
718 |
|
|
mib[1] = KERN_INTRCNT; |
719 |
|
|
mib[2] = KERN_INTRCNT_CNT; |
720 |
|
|
mib[3] = i; |
721 |
|
|
siz = sizeof(cnt); |
722 |
|
|
if (sysctl(mib, 4, &cnt, &siz, NULL, 0) < 0) { |
723 |
|
|
warnx("could not read kern.intrcnt.cnt.%d", i); |
724 |
|
|
return; |
725 |
|
|
} |
726 |
|
|
|
727 |
|
|
if (cnt || zflag) |
728 |
|
|
(void)printf("%-16.16s %20llu %8llu\n", intrname, |
729 |
|
|
cnt, cnt / uptime); |
730 |
|
|
inttotal += cnt; |
731 |
|
|
} |
732 |
|
|
|
733 |
|
|
(void)printf("%-16s %20llu %8llu\n", "Total", inttotal, |
734 |
|
|
inttotal / uptime); |
735 |
|
|
} |
736 |
|
|
|
737 |
|
|
/* |
738 |
|
|
* These names are defined in <sys/malloc.h>. |
739 |
|
|
*/ |
740 |
|
|
const char *kmemnames[] = INITKMEMNAMES; |
741 |
|
|
|
742 |
|
|
void |
743 |
|
|
domem(void) |
744 |
|
|
{ |
745 |
|
|
struct kmembuckets buckets[MINBUCKET + 16], *kp; |
746 |
|
|
struct kmemstats kmemstats[M_LAST], *ks; |
747 |
|
|
int i, j, len, size, first, mib[4]; |
748 |
|
|
u_long totuse = 0, totfree = 0; |
749 |
|
|
char buf[BUFSIZ], *bufp, *ap; |
750 |
|
|
quad_t totreq = 0; |
751 |
|
|
const char *name; |
752 |
|
|
size_t siz; |
753 |
|
|
|
754 |
|
|
if (memf == NULL && nlistf == NULL) { |
755 |
|
|
mib[0] = CTL_KERN; |
756 |
|
|
mib[1] = KERN_MALLOCSTATS; |
757 |
|
|
mib[2] = KERN_MALLOC_BUCKETS; |
758 |
|
|
siz = sizeof(buf); |
759 |
|
|
if (sysctl(mib, 3, buf, &siz, NULL, 0) < 0) { |
760 |
|
|
warnx("could not read kern.malloc.buckets"); |
761 |
|
|
return; |
762 |
|
|
} |
763 |
|
|
|
764 |
|
|
bufp = buf; |
765 |
|
|
mib[2] = KERN_MALLOC_BUCKET; |
766 |
|
|
siz = sizeof(struct kmembuckets); |
767 |
|
|
i = 0; |
768 |
|
|
while ((ap = strsep(&bufp, ",")) != NULL) { |
769 |
|
|
const char *errstr; |
770 |
|
|
|
771 |
|
|
mib[3] = strtonum(ap, 0, INT_MAX, &errstr); |
772 |
|
|
if (errstr) { |
773 |
|
|
warnx("kernel lied about %d being a number", mib[3]); |
774 |
|
|
return; |
775 |
|
|
} |
776 |
|
|
|
777 |
|
|
if (sysctl(mib, 4, &buckets[MINBUCKET + i], &siz, |
778 |
|
|
NULL, 0) < 0) { |
779 |
|
|
warn("could not read kern.malloc.bucket.%d", mib[3]); |
780 |
|
|
return; |
781 |
|
|
} |
782 |
|
|
i++; |
783 |
|
|
} |
784 |
|
|
} else { |
785 |
|
|
kread(X_KMEMBUCKETS, buckets, sizeof(buckets)); |
786 |
|
|
} |
787 |
|
|
|
788 |
|
|
for (first = 1, i = MINBUCKET, kp = &buckets[i]; i < MINBUCKET + 16; |
789 |
|
|
i++, kp++) { |
790 |
|
|
if (kp->kb_calls == 0 && !verbose) |
791 |
|
|
continue; |
792 |
|
|
if (first) { |
793 |
|
|
(void)printf("Memory statistics by bucket size\n"); |
794 |
|
|
(void)printf( |
795 |
|
|
" Size In Use Free Requests HighWater Couldfree\n"); |
796 |
|
|
first = 0; |
797 |
|
|
} |
798 |
|
|
size = 1 << i; |
799 |
|
|
(void)printf("%8d %8llu %6llu %18llu %7llu %10llu\n", size, |
800 |
|
|
(unsigned long long)(kp->kb_total - kp->kb_totalfree), |
801 |
|
|
(unsigned long long)kp->kb_totalfree, |
802 |
|
|
(unsigned long long)kp->kb_calls, |
803 |
|
|
(unsigned long long)kp->kb_highwat, |
804 |
|
|
(unsigned long long)kp->kb_couldfree); |
805 |
|
|
totfree += size * kp->kb_totalfree; |
806 |
|
|
} |
807 |
|
|
|
808 |
|
|
/* |
809 |
|
|
* If kmem statistics are not being gathered by the kernel, |
810 |
|
|
* first will still be 1. |
811 |
|
|
*/ |
812 |
|
|
if (first) { |
813 |
|
|
printf( |
814 |
|
|
"Kmem statistics are not being gathered by the kernel.\n"); |
815 |
|
|
return; |
816 |
|
|
} |
817 |
|
|
|
818 |
|
|
if (memf == NULL && nlistf == NULL) { |
819 |
|
|
memset(kmemstats, 0, sizeof(kmemstats)); |
820 |
|
|
for (i = 0; i < M_LAST; i++) { |
821 |
|
|
mib[0] = CTL_KERN; |
822 |
|
|
mib[1] = KERN_MALLOCSTATS; |
823 |
|
|
mib[2] = KERN_MALLOC_KMEMSTATS; |
824 |
|
|
mib[3] = i; |
825 |
|
|
siz = sizeof(struct kmemstats); |
826 |
|
|
|
827 |
|
|
/* |
828 |
|
|
* Skip errors -- these are presumed to be unallocated |
829 |
|
|
* entries. |
830 |
|
|
*/ |
831 |
|
|
if (sysctl(mib, 4, &kmemstats[i], &siz, NULL, 0) < 0) |
832 |
|
|
continue; |
833 |
|
|
} |
834 |
|
|
} else { |
835 |
|
|
kread(X_KMEMSTAT, kmemstats, sizeof(kmemstats)); |
836 |
|
|
} |
837 |
|
|
|
838 |
|
|
(void)printf("\nMemory usage type by bucket size\n"); |
839 |
|
|
(void)printf(" Size Type(s)\n"); |
840 |
|
|
kp = &buckets[MINBUCKET]; |
841 |
|
|
for (j = 1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1, kp++) { |
842 |
|
|
if (kp->kb_calls == 0) |
843 |
|
|
continue; |
844 |
|
|
first = 1; |
845 |
|
|
len = 8; |
846 |
|
|
for (i = 0, ks = &kmemstats[0]; i < M_LAST; i++, ks++) { |
847 |
|
|
if (ks->ks_calls == 0) |
848 |
|
|
continue; |
849 |
|
|
if ((ks->ks_size & j) == 0) |
850 |
|
|
continue; |
851 |
|
|
name = kmemnames[i] ? kmemnames[i] : "undefined"; |
852 |
|
|
len += 2 + strlen(name); |
853 |
|
|
if (first) |
854 |
|
|
printf("%8d %s", j, name); |
855 |
|
|
else |
856 |
|
|
printf(","); |
857 |
|
|
if (len >= 80) { |
858 |
|
|
printf("\n\t "); |
859 |
|
|
len = 10 + strlen(name); |
860 |
|
|
} |
861 |
|
|
if (!first) |
862 |
|
|
printf(" %s", name); |
863 |
|
|
first = 0; |
864 |
|
|
} |
865 |
|
|
printf("\n"); |
866 |
|
|
} |
867 |
|
|
|
868 |
|
|
(void)printf( |
869 |
|
|
"\nMemory statistics by type Type Kern\n"); |
870 |
|
|
(void)printf( |
871 |
|
|
" Type InUse MemUse HighUse Limit Requests Limit Limit Size(s)\n"); |
872 |
|
|
for (i = 0, ks = &kmemstats[0]; i < M_LAST; i++, ks++) { |
873 |
|
|
if (ks->ks_calls == 0) |
874 |
|
|
continue; |
875 |
|
|
(void)printf("%14s%6ld%6ldK%7ldK%6ldK%9ld%5u%6u", |
876 |
|
|
kmemnames[i] ? kmemnames[i] : "undefined", |
877 |
|
|
ks->ks_inuse, (ks->ks_memuse + 1023) / 1024, |
878 |
|
|
(ks->ks_maxused + 1023) / 1024, |
879 |
|
|
(ks->ks_limit + 1023) / 1024, ks->ks_calls, |
880 |
|
|
ks->ks_limblocks, ks->ks_mapblocks); |
881 |
|
|
first = 1; |
882 |
|
|
for (j = 1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1) { |
883 |
|
|
if ((ks->ks_size & j) == 0) |
884 |
|
|
continue; |
885 |
|
|
if (first) |
886 |
|
|
printf(" %d", j); |
887 |
|
|
else |
888 |
|
|
printf(",%d", j); |
889 |
|
|
first = 0; |
890 |
|
|
} |
891 |
|
|
printf("\n"); |
892 |
|
|
totuse += ks->ks_memuse; |
893 |
|
|
totreq += ks->ks_calls; |
894 |
|
|
} |
895 |
|
|
(void)printf("\nMemory Totals: In Use Free Requests\n"); |
896 |
|
|
(void)printf(" %7luK %6luK %8qu\n", |
897 |
|
|
(totuse + 1023) / 1024, (totfree + 1023) / 1024, totreq); |
898 |
|
|
} |
899 |
|
|
|
900 |
|
|
static void |
901 |
|
|
print_pool(struct kinfo_pool *pp, char *name) |
902 |
|
|
{ |
903 |
|
|
static int first = 1; |
904 |
|
|
char maxp[32]; |
905 |
|
|
int ovflw; |
906 |
|
|
|
907 |
|
|
if (first) { |
908 |
|
|
(void)printf("Memory resource pool statistics\n"); |
909 |
|
|
(void)printf( |
910 |
|
|
"%-11s%5s%9s%5s%9s%6s%6s%6s%6s%6s%6s%5s\n", |
911 |
|
|
"Name", |
912 |
|
|
"Size", |
913 |
|
|
"Requests", |
914 |
|
|
"Fail", |
915 |
|
|
"InUse", |
916 |
|
|
"Pgreq", |
917 |
|
|
"Pgrel", |
918 |
|
|
"Npage", |
919 |
|
|
"Hiwat", |
920 |
|
|
"Minpg", |
921 |
|
|
"Maxpg", |
922 |
|
|
"Idle"); |
923 |
|
|
first = 0; |
924 |
|
|
} |
925 |
|
|
|
926 |
|
|
/* Skip unused pools unless verbose output. */ |
927 |
|
|
if (pp->pr_nget == 0 && !verbose) |
928 |
|
|
return; |
929 |
|
|
|
930 |
|
|
if (pp->pr_maxpages == UINT_MAX) |
931 |
|
|
snprintf(maxp, sizeof maxp, "inf"); |
932 |
|
|
else |
933 |
|
|
snprintf(maxp, sizeof maxp, "%u", pp->pr_maxpages); |
934 |
|
|
/* |
935 |
|
|
* Print single word. `ovflow' is number of characters didn't fit |
936 |
|
|
* on the last word. `fmt' is a format string to print this word. |
937 |
|
|
* It must contain asterisk for field width. `width' is a width |
938 |
|
|
* occupied by this word. `fixed' is a number of constant chars in |
939 |
|
|
* `fmt'. `val' is a value to be printed using format string `fmt'. |
940 |
|
|
*/ |
941 |
|
|
#define PRWORD(ovflw, fmt, width, fixed, val) do { \ |
942 |
|
|
(ovflw) += printf((fmt), \ |
943 |
|
|
(width) - (fixed) - (ovflw) > 0 ? \ |
944 |
|
|
(width) - (fixed) - (ovflw) : 0, \ |
945 |
|
|
(val)) - (width); \ |
946 |
|
|
if ((ovflw) < 0) \ |
947 |
|
|
(ovflw) = 0; \ |
948 |
|
|
} while (/* CONSTCOND */0) |
949 |
|
|
|
950 |
|
|
ovflw = 0; |
951 |
|
|
PRWORD(ovflw, "%-*s", 11, 0, name); |
952 |
|
|
PRWORD(ovflw, " %*u", 5, 1, pp->pr_size); |
953 |
|
|
PRWORD(ovflw, " %*lu", 9, 1, pp->pr_nget); |
954 |
|
|
PRWORD(ovflw, " %*lu", 5, 1, pp->pr_nfail); |
955 |
|
|
PRWORD(ovflw, " %*lu", 9, 1, pp->pr_nget - pp->pr_nput); |
956 |
|
|
PRWORD(ovflw, " %*lu", 6, 1, pp->pr_npagealloc); |
957 |
|
|
PRWORD(ovflw, " %*lu", 6, 1, pp->pr_npagefree); |
958 |
|
|
PRWORD(ovflw, " %*d", 6, 1, pp->pr_npages); |
959 |
|
|
PRWORD(ovflw, " %*d", 6, 1, pp->pr_hiwat); |
960 |
|
|
PRWORD(ovflw, " %*d", 6, 1, pp->pr_minpages); |
961 |
|
|
PRWORD(ovflw, " %*s", 6, 1, maxp); |
962 |
|
|
PRWORD(ovflw, " %*lu\n", 5, 1, pp->pr_nidle); |
963 |
|
|
} |
964 |
|
|
|
965 |
|
|
static void dopool_kvm(void); |
966 |
|
|
static void dopool_sysctl(void); |
967 |
|
|
|
968 |
|
|
void |
969 |
|
|
dopool(void) |
970 |
|
|
{ |
971 |
|
|
if (nlistf == NULL && memf == NULL) |
972 |
|
|
dopool_sysctl(); |
973 |
|
|
else |
974 |
|
|
dopool_kvm(); |
975 |
|
|
} |
976 |
|
|
|
977 |
|
|
void |
978 |
|
|
dopool_sysctl(void) |
979 |
|
|
{ |
980 |
|
|
int mib[4], npools, i; |
981 |
|
|
long total = 0, inuse = 0; |
982 |
|
|
struct kinfo_pool pool; |
983 |
|
|
size_t size; |
984 |
|
|
|
985 |
|
|
mib[0] = CTL_KERN; |
986 |
|
|
mib[1] = KERN_POOL; |
987 |
|
|
mib[2] = KERN_POOL_NPOOLS; |
988 |
|
|
size = sizeof(npools); |
989 |
|
|
if (sysctl(mib, 3, &npools, &size, NULL, 0) < 0) { |
990 |
|
|
warn("can't figure out number of pools in kernel"); |
991 |
|
|
return; |
992 |
|
|
} |
993 |
|
|
|
994 |
|
|
for (i = 1; npools; i++) { |
995 |
|
|
char name[32]; |
996 |
|
|
|
997 |
|
|
mib[0] = CTL_KERN; |
998 |
|
|
mib[1] = KERN_POOL; |
999 |
|
|
mib[2] = KERN_POOL_POOL; |
1000 |
|
|
mib[3] = i; |
1001 |
|
|
size = sizeof(pool); |
1002 |
|
|
if (sysctl(mib, 4, &pool, &size, NULL, 0) < 0) { |
1003 |
|
|
if (errno == ENOENT) |
1004 |
|
|
continue; |
1005 |
|
|
warn("error getting pool"); |
1006 |
|
|
return; |
1007 |
|
|
} |
1008 |
|
|
npools--; |
1009 |
|
|
mib[2] = KERN_POOL_NAME; |
1010 |
|
|
size = sizeof(name); |
1011 |
|
|
if (sysctl(mib, 4, &name, &size, NULL, 0) < 0) { |
1012 |
|
|
warn("error getting pool name"); |
1013 |
|
|
return; |
1014 |
|
|
} |
1015 |
|
|
print_pool(&pool, name); |
1016 |
|
|
|
1017 |
|
|
inuse += (pool.pr_nget - pool.pr_nput) * pool.pr_size; |
1018 |
|
|
total += pool.pr_npages * pool.pr_pgsize; |
1019 |
|
|
} |
1020 |
|
|
|
1021 |
|
|
inuse /= 1024; |
1022 |
|
|
total /= 1024; |
1023 |
|
|
printf("\nIn use %ldK, total allocated %ldK; utilization %.1f%%\n", |
1024 |
|
|
inuse, total, (double)(100 * inuse) / total); |
1025 |
|
|
} |
1026 |
|
|
|
1027 |
|
|
void |
1028 |
|
|
dopool_kvm(void) |
1029 |
|
|
{ |
1030 |
|
|
SIMPLEQ_HEAD(,pool) pool_head; |
1031 |
|
|
struct pool pool, *pp = &pool; |
1032 |
|
|
struct kinfo_pool pi; |
1033 |
|
|
long total = 0, inuse = 0; |
1034 |
|
|
u_long addr; |
1035 |
|
|
|
1036 |
|
|
kread(X_POOLHEAD, &pool_head, sizeof(pool_head)); |
1037 |
|
|
addr = (u_long)SIMPLEQ_FIRST(&pool_head); |
1038 |
|
|
|
1039 |
|
|
while (addr != 0) { |
1040 |
|
|
char name[32]; |
1041 |
|
|
|
1042 |
|
|
if (kvm_read(kd, addr, (void *)pp, sizeof *pp) != sizeof *pp) { |
1043 |
|
|
(void)fprintf(stderr, |
1044 |
|
|
"vmstat: pool chain trashed: %s\n", |
1045 |
|
|
kvm_geterr(kd)); |
1046 |
|
|
exit(1); |
1047 |
|
|
} |
1048 |
|
|
if (kvm_read(kd, (u_long)pp->pr_wchan, name, sizeof name) < 0) { |
1049 |
|
|
(void)fprintf(stderr, |
1050 |
|
|
"vmstat: pool name trashed: %s\n", |
1051 |
|
|
kvm_geterr(kd)); |
1052 |
|
|
exit(1); |
1053 |
|
|
} |
1054 |
|
|
name[31] = '\0'; |
1055 |
|
|
|
1056 |
|
|
memset(&pi, 0, sizeof(pi)); |
1057 |
|
|
pi.pr_size = pp->pr_size; |
1058 |
|
|
pi.pr_pgsize = pp->pr_pgsize; |
1059 |
|
|
pi.pr_itemsperpage = pp->pr_itemsperpage; |
1060 |
|
|
pi.pr_npages = pp->pr_npages; |
1061 |
|
|
pi.pr_minpages = pp->pr_minpages; |
1062 |
|
|
pi.pr_maxpages = pp->pr_maxpages; |
1063 |
|
|
pi.pr_hardlimit = pp->pr_hardlimit; |
1064 |
|
|
pi.pr_nout = pp->pr_nout; |
1065 |
|
|
pi.pr_nitems = pp->pr_nitems; |
1066 |
|
|
pi.pr_nget = pp->pr_nget; |
1067 |
|
|
pi.pr_nput = pp->pr_nput; |
1068 |
|
|
pi.pr_nfail = pp->pr_nfail; |
1069 |
|
|
pi.pr_npagealloc = pp->pr_npagealloc; |
1070 |
|
|
pi.pr_npagefree = pp->pr_npagefree; |
1071 |
|
|
pi.pr_hiwat = pp->pr_hiwat; |
1072 |
|
|
pi.pr_nidle = pp->pr_nidle; |
1073 |
|
|
|
1074 |
|
|
print_pool(&pi, name); |
1075 |
|
|
|
1076 |
|
|
inuse += (pi.pr_nget - pi.pr_nput) * pi.pr_size; |
1077 |
|
|
total += pi.pr_npages * pi.pr_pgsize; |
1078 |
|
|
|
1079 |
|
|
addr = (u_long)SIMPLEQ_NEXT(pp, pr_poollist); |
1080 |
|
|
} |
1081 |
|
|
|
1082 |
|
|
inuse /= 1024; |
1083 |
|
|
total /= 1024; |
1084 |
|
|
printf("\nIn use %ldK, total allocated %ldK; utilization %.1f%%\n", |
1085 |
|
|
inuse, total, (double)(100 * inuse) / total); |
1086 |
|
|
} |
1087 |
|
|
|
1088 |
|
|
/* |
1089 |
|
|
* kread reads something from the kernel, given its nlist index. |
1090 |
|
|
*/ |
1091 |
|
|
void |
1092 |
|
|
kread(int nlx, void *addr, size_t size) |
1093 |
|
|
{ |
1094 |
|
|
char *sym; |
1095 |
|
|
|
1096 |
|
|
if (namelist[nlx].n_type == 0 || namelist[nlx].n_value == 0) { |
1097 |
|
|
sym = namelist[nlx].n_name; |
1098 |
|
|
if (*sym == '_') |
1099 |
|
|
++sym; |
1100 |
|
|
errx(1, "symbol %s not defined", sym); |
1101 |
|
|
} |
1102 |
|
|
if (kvm_read(kd, namelist[nlx].n_value, addr, size) != size) { |
1103 |
|
|
sym = namelist[nlx].n_name; |
1104 |
|
|
if (*sym == '_') |
1105 |
|
|
++sym; |
1106 |
|
|
errx(1, "%s: %s", sym, kvm_geterr(kd)); |
1107 |
|
|
} |
1108 |
|
|
} |
1109 |
|
|
|
1110 |
|
|
void |
1111 |
|
|
usage(void) |
1112 |
|
|
{ |
1113 |
|
|
(void)fprintf(stderr, "usage: %s [-fimstvz] [-c count] [-M core] " |
1114 |
|
|
"[-N system] [-w wait] [disk ...]\n", __progname); |
1115 |
|
|
exit(1); |
1116 |
|
|
} |