vmstat.c revision 1.78 1 1.78 jhawk /* $NetBSD: vmstat.c,v 1.78 2001/04/05 20:04:03 jhawk Exp $ */
2 1.45 thorpej
3 1.45 thorpej /*-
4 1.66 cgd * Copyright (c) 1998, 2000 The NetBSD Foundation, Inc.
5 1.45 thorpej * All rights reserved.
6 1.45 thorpej *
7 1.45 thorpej * This code is derived from software contributed to The NetBSD Foundation
8 1.45 thorpej * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 1.45 thorpej * NASA Ames Research Center.
10 1.45 thorpej *
11 1.45 thorpej * Redistribution and use in source and binary forms, with or without
12 1.45 thorpej * modification, are permitted provided that the following conditions
13 1.45 thorpej * are met:
14 1.45 thorpej * 1. Redistributions of source code must retain the above copyright
15 1.45 thorpej * notice, this list of conditions and the following disclaimer.
16 1.45 thorpej * 2. Redistributions in binary form must reproduce the above copyright
17 1.45 thorpej * notice, this list of conditions and the following disclaimer in the
18 1.45 thorpej * documentation and/or other materials provided with the distribution.
19 1.45 thorpej * 3. All advertising materials mentioning features or use of this software
20 1.45 thorpej * must display the following acknowledgement:
21 1.45 thorpej * This product includes software developed by the NetBSD
22 1.45 thorpej * Foundation, Inc. and its contributors.
23 1.45 thorpej * 4. Neither the name of The NetBSD Foundation nor the names of its
24 1.45 thorpej * contributors may be used to endorse or promote products derived
25 1.45 thorpej * from this software without specific prior written permission.
26 1.45 thorpej *
27 1.45 thorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 1.45 thorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 1.45 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 1.45 thorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 1.45 thorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 1.45 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 1.45 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 1.45 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 1.45 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 1.45 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 1.45 thorpej * POSSIBILITY OF SUCH DAMAGE.
38 1.45 thorpej */
39 1.21 cgd
40 1.1 cgd /*
41 1.13 cgd * Copyright (c) 1980, 1986, 1991, 1993
42 1.13 cgd * The Regents of the University of California. All rights reserved.
43 1.1 cgd *
44 1.1 cgd * Redistribution and use in source and binary forms, with or without
45 1.1 cgd * modification, are permitted provided that the following conditions
46 1.1 cgd * are met:
47 1.1 cgd * 1. Redistributions of source code must retain the above copyright
48 1.1 cgd * notice, this list of conditions and the following disclaimer.
49 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
50 1.1 cgd * notice, this list of conditions and the following disclaimer in the
51 1.1 cgd * documentation and/or other materials provided with the distribution.
52 1.1 cgd * 3. All advertising materials mentioning features or use of this software
53 1.1 cgd * must display the following acknowledgement:
54 1.1 cgd * This product includes software developed by the University of
55 1.1 cgd * California, Berkeley and its contributors.
56 1.1 cgd * 4. Neither the name of the University nor the names of its contributors
57 1.1 cgd * may be used to endorse or promote products derived from this software
58 1.1 cgd * without specific prior written permission.
59 1.1 cgd *
60 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
61 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
62 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
63 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
64 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
65 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
66 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
67 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
68 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
69 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
70 1.1 cgd * SUCH DAMAGE.
71 1.1 cgd */
72 1.1 cgd
73 1.38 mrg #include <sys/cdefs.h>
74 1.1 cgd #ifndef lint
75 1.38 mrg __COPYRIGHT("@(#) Copyright (c) 1980, 1986, 1991, 1993\n\
76 1.38 mrg The Regents of the University of California. All rights reserved.\n");
77 1.1 cgd #endif /* not lint */
78 1.1 cgd
79 1.1 cgd #ifndef lint
80 1.21 cgd #if 0
81 1.37 mrg static char sccsid[] = "@(#)vmstat.c 8.2 (Berkeley) 3/1/95";
82 1.21 cgd #else
83 1.78 jhawk __RCSID("$NetBSD: vmstat.c,v 1.78 2001/04/05 20:04:03 jhawk Exp $");
84 1.21 cgd #endif
85 1.1 cgd #endif /* not lint */
86 1.57 thorpej
87 1.57 thorpej #define __POOL_EXPOSE
88 1.1 cgd
89 1.1 cgd #include <sys/param.h>
90 1.1 cgd #include <sys/time.h>
91 1.1 cgd #include <sys/proc.h>
92 1.1 cgd #include <sys/user.h>
93 1.1 cgd #include <sys/dkstat.h>
94 1.1 cgd #include <sys/buf.h>
95 1.1 cgd #include <sys/namei.h>
96 1.1 cgd #include <sys/malloc.h>
97 1.1 cgd #include <sys/ioctl.h>
98 1.64 perry #include <sys/sched.h>
99 1.13 cgd #include <sys/sysctl.h>
100 1.18 pk #include <sys/device.h>
101 1.51 pk #include <sys/pool.h>
102 1.67 mrg
103 1.67 mrg #include <uvm/uvm_extern.h>
104 1.67 mrg #include <uvm/uvm_stat.h>
105 1.67 mrg
106 1.45 thorpej #include <err.h>
107 1.55 kleink #include <fcntl.h>
108 1.1 cgd #include <time.h>
109 1.1 cgd #include <nlist.h>
110 1.1 cgd #include <kvm.h>
111 1.1 cgd #include <errno.h>
112 1.1 cgd #include <unistd.h>
113 1.22 jtc #include <signal.h>
114 1.1 cgd #include <stdio.h>
115 1.1 cgd #include <ctype.h>
116 1.1 cgd #include <stdlib.h>
117 1.1 cgd #include <string.h>
118 1.1 cgd #include <paths.h>
119 1.13 cgd #include <limits.h>
120 1.29 thorpej #include "dkstats.h"
121 1.45 thorpej
122 1.13 cgd struct nlist namelist[] = {
123 1.65 itojun #define X_BOOTTIME 0
124 1.1 cgd { "_boottime" },
125 1.75 enami #define X_HZ 1
126 1.1 cgd { "_hz" },
127 1.75 enami #define X_STATHZ 2
128 1.13 cgd { "_stathz" },
129 1.75 enami #define X_NCHSTATS 3
130 1.1 cgd { "_nchstats" },
131 1.65 itojun #define X_INTRNAMES 4
132 1.1 cgd { "_intrnames" },
133 1.65 itojun #define X_EINTRNAMES 5
134 1.1 cgd { "_eintrnames" },
135 1.65 itojun #define X_INTRCNT 6
136 1.1 cgd { "_intrcnt" },
137 1.65 itojun #define X_EINTRCNT 7
138 1.1 cgd { "_eintrcnt" },
139 1.65 itojun #define X_KMEMSTAT 8
140 1.1 cgd { "_kmemstats" },
141 1.65 itojun #define X_KMEMBUCKETS 9
142 1.1 cgd { "_bucket" },
143 1.75 enami #define X_ALLEVENTS 10
144 1.18 pk { "_allevents" },
145 1.75 enami #define X_POOLHEAD 11
146 1.51 pk { "_pool_head" },
147 1.65 itojun #define X_UVMEXP 12
148 1.58 thorpej { "_uvmexp" },
149 1.75 enami #define X_END 13
150 1.23 phil #if defined(pc532)
151 1.23 phil #define X_IVT (X_END)
152 1.23 phil { "_ivt" },
153 1.23 phil #endif
154 1.1 cgd { "" },
155 1.1 cgd };
156 1.1 cgd
157 1.41 mrg struct uvmexp uvmexp, ouvmexp;
158 1.73 simonb int ndrives;
159 1.1 cgd
160 1.1 cgd int winlines = 20;
161 1.1 cgd
162 1.13 cgd kvm_t *kd;
163 1.13 cgd
164 1.1 cgd #define FORKSTAT 0x01
165 1.1 cgd #define INTRSTAT 0x02
166 1.1 cgd #define MEMSTAT 0x04
167 1.1 cgd #define SUMSTAT 0x08
168 1.66 cgd #define EVCNTSTAT 0x10
169 1.1 cgd #define VMSTAT 0x20
170 1.45 thorpej #define HISTLIST 0x40
171 1.45 thorpej #define HISTDUMP 0x80
172 1.1 cgd
173 1.73 simonb void cpustats(void);
174 1.73 simonb void dkstats(void);
175 1.73 simonb void doevcnt(int verbose);
176 1.73 simonb void dointr(int verbose);
177 1.73 simonb void domem(void);
178 1.73 simonb void dopool(void);
179 1.73 simonb void dosum(void);
180 1.73 simonb void dovmstat(u_int, int);
181 1.73 simonb void kread(int, void *, size_t);
182 1.73 simonb void needhdr(int);
183 1.73 simonb long getuptime(void);
184 1.73 simonb void printhdr(void);
185 1.73 simonb long pct(long, long);
186 1.73 simonb void usage(void);
187 1.73 simonb void doforkst(void);
188 1.73 simonb
189 1.73 simonb void hist_traverse(int, const char *);
190 1.73 simonb void hist_dodump(struct uvm_history *);
191 1.73 simonb
192 1.73 simonb int main(int, char **);
193 1.73 simonb char **choosedrives(char **);
194 1.38 mrg
195 1.29 thorpej /* Namelist and memory file names. */
196 1.29 thorpej char *nlistf, *memf;
197 1.29 thorpej
198 1.47 mrg /* allow old usage [vmstat 1] */
199 1.47 mrg #define BACKWARD_COMPATIBILITY
200 1.47 mrg
201 1.38 mrg int
202 1.75 enami main(int argc, char *argv[])
203 1.1 cgd {
204 1.66 cgd int c, todo, verbose;
205 1.1 cgd u_int interval;
206 1.1 cgd int reps;
207 1.75 enami char errbuf[_POSIX2_LINE_MAX];
208 1.75 enami gid_t egid = getegid();
209 1.45 thorpej const char *histname = NULL;
210 1.1 cgd
211 1.48 mrg (void)setegid(getgid());
212 1.13 cgd memf = nlistf = NULL;
213 1.66 cgd interval = reps = todo = verbose = 0;
214 1.66 cgd while ((c = getopt(argc, argv, "c:efh:HilM:mN:svw:")) != -1) {
215 1.1 cgd switch (c) {
216 1.1 cgd case 'c':
217 1.1 cgd reps = atoi(optarg);
218 1.1 cgd break;
219 1.66 cgd case 'e':
220 1.66 cgd todo |= EVCNTSTAT;
221 1.66 cgd break;
222 1.1 cgd case 'f':
223 1.1 cgd todo |= FORKSTAT;
224 1.1 cgd break;
225 1.45 thorpej case 'h':
226 1.45 thorpej histname = optarg;
227 1.45 thorpej /* FALLTHROUGH */
228 1.45 thorpej case 'H':
229 1.45 thorpej todo |= HISTDUMP;
230 1.45 thorpej break;
231 1.1 cgd case 'i':
232 1.1 cgd todo |= INTRSTAT;
233 1.1 cgd break;
234 1.45 thorpej case 'l':
235 1.45 thorpej todo |= HISTLIST;
236 1.45 thorpej break;
237 1.1 cgd case 'M':
238 1.13 cgd memf = optarg;
239 1.1 cgd break;
240 1.1 cgd case 'm':
241 1.1 cgd todo |= MEMSTAT;
242 1.1 cgd break;
243 1.1 cgd case 'N':
244 1.13 cgd nlistf = optarg;
245 1.1 cgd break;
246 1.1 cgd case 's':
247 1.1 cgd todo |= SUMSTAT;
248 1.1 cgd break;
249 1.66 cgd case 'v':
250 1.66 cgd verbose = 1;
251 1.66 cgd break;
252 1.1 cgd case 'w':
253 1.1 cgd interval = atoi(optarg);
254 1.1 cgd break;
255 1.1 cgd case '?':
256 1.1 cgd default:
257 1.1 cgd usage();
258 1.1 cgd }
259 1.1 cgd }
260 1.1 cgd argc -= optind;
261 1.1 cgd argv += optind;
262 1.1 cgd
263 1.1 cgd if (todo == 0)
264 1.1 cgd todo = VMSTAT;
265 1.1 cgd
266 1.13 cgd /*
267 1.48 mrg * Discard setgid privileges. If not the running kernel, we toss
268 1.48 mrg * them away totally so that bad guys can't print interesting stuff
269 1.48 mrg * from kernel memory, otherwise switch back to kmem for the
270 1.48 mrg * duration of the kvm_openfiles() call.
271 1.13 cgd */
272 1.13 cgd if (nlistf != NULL || memf != NULL)
273 1.48 mrg (void)setgid(getgid());
274 1.48 mrg else
275 1.48 mrg (void)setegid(egid);
276 1.13 cgd
277 1.75 enami kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
278 1.75 enami if (kd == NULL)
279 1.48 mrg errx(1, "kvm_openfiles: %s\n", errbuf);
280 1.48 mrg
281 1.48 mrg if (nlistf == NULL && memf == NULL) {
282 1.48 mrg if (todo & VMSTAT)
283 1.48 mrg (void)setegid(getgid()); /* XXX: dkinit */
284 1.48 mrg else
285 1.48 mrg (void)setgid(getgid());
286 1.1 cgd }
287 1.1 cgd
288 1.13 cgd if ((c = kvm_nlist(kd, namelist)) != 0) {
289 1.1 cgd if (c > 0) {
290 1.1 cgd (void)fprintf(stderr,
291 1.13 cgd "vmstat: undefined symbols:");
292 1.13 cgd for (c = 0;
293 1.75 enami c < sizeof(namelist) / sizeof(namelist[0]); c++)
294 1.13 cgd if (namelist[c].n_type == 0)
295 1.13 cgd fprintf(stderr, " %s",
296 1.13 cgd namelist[c].n_name);
297 1.1 cgd (void)fputc('\n', stderr);
298 1.1 cgd } else
299 1.1 cgd (void)fprintf(stderr, "vmstat: kvm_nlist: %s\n",
300 1.13 cgd kvm_geterr(kd));
301 1.1 cgd exit(1);
302 1.1 cgd }
303 1.1 cgd
304 1.1 cgd if (todo & VMSTAT) {
305 1.1 cgd struct winsize winsize;
306 1.1 cgd
307 1.49 drochner dkinit(0, egid); /* Initialize disk stats, no disks selected. */
308 1.49 drochner
309 1.49 drochner (void)setgid(getgid()); /* don't need privs anymore */
310 1.49 drochner
311 1.29 thorpej argv = choosedrives(argv); /* Select disks. */
312 1.1 cgd winsize.ws_row = 0;
313 1.47 mrg (void)ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&winsize);
314 1.1 cgd if (winsize.ws_row > 0)
315 1.1 cgd winlines = winsize.ws_row;
316 1.1 cgd
317 1.1 cgd }
318 1.1 cgd
319 1.1 cgd #ifdef BACKWARD_COMPATIBILITY
320 1.1 cgd if (*argv) {
321 1.1 cgd interval = atoi(*argv);
322 1.1 cgd if (*++argv)
323 1.1 cgd reps = atoi(*argv);
324 1.1 cgd }
325 1.1 cgd #endif
326 1.1 cgd
327 1.1 cgd if (interval) {
328 1.1 cgd if (!reps)
329 1.1 cgd reps = -1;
330 1.1 cgd } else if (reps)
331 1.1 cgd interval = 1;
332 1.1 cgd
333 1.78 jhawk
334 1.78 jhawk /*
335 1.78 jhawk * Statistics dumping is incompatible with the default
336 1.78 jhawk * VMSTAT/dovmstat() output. So perform the interval/reps handling
337 1.78 jhawk * for it here.
338 1.78 jhawk */
339 1.78 jhawk if ((todo & VMSTAT) == 0)
340 1.78 jhawk for (;;) {
341 1.78 jhawk if (todo & (HISTLIST|HISTDUMP)) {
342 1.78 jhawk if ((todo & (HISTLIST|HISTDUMP)) ==
343 1.78 jhawk (HISTLIST|HISTDUMP))
344 1.78 jhawk errx(1, "you may list or dump, but not both!");
345 1.78 jhawk hist_traverse(todo, histname);
346 1.78 jhawk }
347 1.78 jhawk if (todo & FORKSTAT)
348 1.78 jhawk doforkst();
349 1.78 jhawk if (todo & MEMSTAT) {
350 1.78 jhawk domem();
351 1.78 jhawk dopool();
352 1.78 jhawk }
353 1.78 jhawk if (todo & SUMSTAT)
354 1.78 jhawk dosum();
355 1.78 jhawk if (todo & INTRSTAT)
356 1.78 jhawk dointr(verbose);
357 1.78 jhawk if (todo & EVCNTSTAT)
358 1.78 jhawk doevcnt(verbose);
359 1.78 jhawk
360 1.78 jhawk if (reps >= 0 && --reps <=0)
361 1.78 jhawk break;
362 1.78 jhawk sleep(interval);
363 1.78 jhawk puts("");
364 1.78 jhawk }
365 1.78 jhawk else
366 1.1 cgd dovmstat(interval, reps);
367 1.1 cgd exit(0);
368 1.1 cgd }
369 1.1 cgd
370 1.1 cgd char **
371 1.73 simonb choosedrives(char **argv)
372 1.1 cgd {
373 1.38 mrg int i;
374 1.1 cgd
375 1.1 cgd /*
376 1.1 cgd * Choose drives to be displayed. Priority goes to (in order) drives
377 1.1 cgd * supplied as arguments, default drives. If everything isn't filled
378 1.1 cgd * in and there are drives not taken care of, display the first few
379 1.1 cgd * that fit.
380 1.1 cgd */
381 1.75 enami #define BACKWARD_COMPATIBILITY
382 1.1 cgd for (ndrives = 0; *argv; ++argv) {
383 1.1 cgd #ifdef BACKWARD_COMPATIBILITY
384 1.1 cgd if (isdigit(**argv))
385 1.1 cgd break;
386 1.1 cgd #endif
387 1.1 cgd for (i = 0; i < dk_ndrive; i++) {
388 1.1 cgd if (strcmp(dr_name[i], *argv))
389 1.1 cgd continue;
390 1.29 thorpej dk_select[i] = 1;
391 1.1 cgd ++ndrives;
392 1.1 cgd break;
393 1.1 cgd }
394 1.1 cgd }
395 1.1 cgd for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
396 1.29 thorpej if (dk_select[i])
397 1.1 cgd continue;
398 1.29 thorpej dk_select[i] = 1;
399 1.1 cgd ++ndrives;
400 1.1 cgd }
401 1.75 enami return (argv);
402 1.1 cgd }
403 1.1 cgd
404 1.1 cgd long
405 1.73 simonb getuptime(void)
406 1.1 cgd {
407 1.30 cgd static time_t now;
408 1.30 cgd static struct timeval boottime;
409 1.1 cgd time_t uptime;
410 1.1 cgd
411 1.30 cgd if (boottime.tv_sec == 0)
412 1.1 cgd kread(X_BOOTTIME, &boottime, sizeof(boottime));
413 1.1 cgd (void)time(&now);
414 1.30 cgd uptime = now - boottime.tv_sec;
415 1.1 cgd if (uptime <= 0 || uptime > 60*60*24*365*10) {
416 1.1 cgd (void)fprintf(stderr,
417 1.1 cgd "vmstat: time makes no sense; namelist must be wrong.\n");
418 1.1 cgd exit(1);
419 1.1 cgd }
420 1.75 enami return (uptime);
421 1.1 cgd }
422 1.1 cgd
423 1.1 cgd int hz, hdrcnt;
424 1.1 cgd
425 1.1 cgd void
426 1.73 simonb dovmstat(u_int interval, int reps)
427 1.1 cgd {
428 1.1 cgd struct vmtotal total;
429 1.1 cgd time_t uptime, halfuptime;
430 1.17 cgd int mib[2];
431 1.17 cgd size_t size;
432 1.41 mrg int pagesize = getpagesize();
433 1.1 cgd
434 1.1 cgd uptime = getuptime();
435 1.1 cgd halfuptime = uptime / 2;
436 1.1 cgd (void)signal(SIGCONT, needhdr);
437 1.1 cgd
438 1.13 cgd if (namelist[X_STATHZ].n_type != 0 && namelist[X_STATHZ].n_value != 0)
439 1.13 cgd kread(X_STATHZ, &hz, sizeof(hz));
440 1.1 cgd if (!hz)
441 1.1 cgd kread(X_HZ, &hz, sizeof(hz));
442 1.1 cgd
443 1.1 cgd for (hdrcnt = 1;;) {
444 1.1 cgd if (!--hdrcnt)
445 1.1 cgd printhdr();
446 1.29 thorpej /* Read new disk statistics */
447 1.29 thorpej dkreadstats();
448 1.58 thorpej kread(X_UVMEXP, &uvmexp, sizeof(uvmexp));
449 1.58 thorpej if (memf != NULL) {
450 1.58 thorpej /*
451 1.58 thorpej * XXX Can't do this if we're reading a crash
452 1.58 thorpej * XXX dump because they're lazily-calculated.
453 1.58 thorpej */
454 1.58 thorpej printf("Unable to get vmtotals from crash dump.\n");
455 1.53 perry memset(&total, 0, sizeof(total));
456 1.58 thorpej } else {
457 1.58 thorpej size = sizeof(total);
458 1.58 thorpej mib[0] = CTL_VM;
459 1.58 thorpej mib[1] = VM_METER;
460 1.58 thorpej if (sysctl(mib, 2, &total, &size, NULL, 0) < 0) {
461 1.58 thorpej printf("Can't get vmtotals: %s\n",
462 1.58 thorpej strerror(errno));
463 1.58 thorpej memset(&total, 0, sizeof(total));
464 1.58 thorpej }
465 1.13 cgd }
466 1.13 cgd (void)printf("%2d%2d%2d",
467 1.13 cgd total.t_rq - 1, total.t_dw + total.t_pw, total.t_sw);
468 1.75 enami #define pgtok(a) (long)((a) * (pagesize >> 10))
469 1.38 mrg #define rate(x) (u_long)(((x) + halfuptime) / uptime) /* round */
470 1.13 cgd (void)printf("%6ld%6ld ",
471 1.1 cgd pgtok(total.t_avm), pgtok(total.t_free));
472 1.42 mrg (void)printf("%4lu ", rate(uvmexp.faults - ouvmexp.faults));
473 1.42 mrg (void)printf("%3lu ", rate(uvmexp.pdreact - ouvmexp.pdreact));
474 1.46 mrg (void)printf("%3lu ", rate(uvmexp.pageins - ouvmexp.pageins));
475 1.44 mrg (void)printf("%4lu ",
476 1.44 mrg rate(uvmexp.pgswapout - ouvmexp.pgswapout));
477 1.44 mrg (void)printf("%4lu ", rate(uvmexp.pdfreed - ouvmexp.pdfreed));
478 1.44 mrg (void)printf("%4lu ", rate(uvmexp.pdscans - ouvmexp.pdscans));
479 1.42 mrg dkstats();
480 1.42 mrg (void)printf("%4lu %4lu %3lu ",
481 1.42 mrg rate(uvmexp.intrs - ouvmexp.intrs),
482 1.42 mrg rate(uvmexp.syscalls - ouvmexp.syscalls),
483 1.42 mrg rate(uvmexp.swtch - ouvmexp.swtch));
484 1.42 mrg cpustats();
485 1.42 mrg (void)printf("\n");
486 1.42 mrg (void)fflush(stdout);
487 1.42 mrg if (reps >= 0 && --reps <= 0)
488 1.42 mrg break;
489 1.42 mrg ouvmexp = uvmexp;
490 1.1 cgd uptime = interval;
491 1.1 cgd /*
492 1.1 cgd * We round upward to avoid losing low-frequency events
493 1.1 cgd * (i.e., >= 1 per interval but < 1 per second).
494 1.1 cgd */
495 1.33 thorpej halfuptime = uptime == 1 ? 0 : (uptime + 1) / 2;
496 1.1 cgd (void)sleep(interval);
497 1.1 cgd }
498 1.1 cgd }
499 1.1 cgd
500 1.38 mrg void
501 1.73 simonb printhdr(void)
502 1.1 cgd {
503 1.38 mrg int i;
504 1.1 cgd
505 1.44 mrg (void)printf(" procs memory page%*s", 23, "");
506 1.29 thorpej if (ndrives > 0)
507 1.70 sommerfe (void)printf("%s %*sfaults cpu\n",
508 1.75 enami ((ndrives > 1) ? "disks" : "disk"),
509 1.75 enami ((ndrives > 1) ? ndrives * 3 - 4 : 0), "");
510 1.1 cgd else
511 1.29 thorpej (void)printf("%*s faults cpu\n",
512 1.75 enami ndrives * 3, "");
513 1.29 thorpej
514 1.44 mrg (void)printf(" r b w avm fre flt re pi po fr sr ");
515 1.1 cgd for (i = 0; i < dk_ndrive; i++)
516 1.29 thorpej if (dk_select[i])
517 1.1 cgd (void)printf("%c%c ", dr_name[i][0],
518 1.1 cgd dr_name[i][strlen(dr_name[i]) - 1]);
519 1.1 cgd (void)printf(" in sy cs us sy id\n");
520 1.1 cgd hdrcnt = winlines - 2;
521 1.1 cgd }
522 1.1 cgd
523 1.1 cgd /*
524 1.1 cgd * Force a header to be prepended to the next output.
525 1.1 cgd */
526 1.1 cgd void
527 1.73 simonb needhdr(int dummy)
528 1.1 cgd {
529 1.1 cgd
530 1.1 cgd hdrcnt = 1;
531 1.1 cgd }
532 1.1 cgd
533 1.38 mrg long
534 1.73 simonb pct(long top, long bot)
535 1.1 cgd {
536 1.13 cgd long ans;
537 1.13 cgd
538 1.1 cgd if (bot == 0)
539 1.75 enami return (0);
540 1.13 cgd ans = (quad_t)top * 100 / bot;
541 1.13 cgd return (ans);
542 1.1 cgd }
543 1.1 cgd
544 1.38 mrg #define PCT(top, bot) (int)pct((long)(top), (long)(bot))
545 1.1 cgd
546 1.1 cgd void
547 1.73 simonb dosum(void)
548 1.1 cgd {
549 1.1 cgd struct nchstats nchstats;
550 1.1 cgd long nchtotal;
551 1.1 cgd
552 1.58 thorpej kread(X_UVMEXP, &uvmexp, sizeof(uvmexp));
553 1.41 mrg
554 1.44 mrg (void)printf("%9u bytes per page\n", uvmexp.pagesize);
555 1.44 mrg
556 1.44 mrg (void)printf("%9u pages managed\n", uvmexp.npages);
557 1.44 mrg (void)printf("%9u pages free\n", uvmexp.free);
558 1.44 mrg (void)printf("%9u pages active\n", uvmexp.active);
559 1.44 mrg (void)printf("%9u pages inactive\n", uvmexp.inactive);
560 1.44 mrg (void)printf("%9u pages paging\n", uvmexp.paging);
561 1.44 mrg (void)printf("%9u pages wired\n", uvmexp.wired);
562 1.63 thorpej (void)printf("%9u zero pages\n", uvmexp.zeropages);
563 1.44 mrg (void)printf("%9u reserve pagedaemon pages\n",
564 1.44 mrg uvmexp.reserve_pagedaemon);
565 1.44 mrg (void)printf("%9u reserve kernel pages\n", uvmexp.reserve_kernel);
566 1.71 simonb (void)printf("%9u anon pager pages\n", uvmexp.anonpages);
567 1.72 simonb (void)printf("%9u vnode page cache pages\n", uvmexp.vnodepages);
568 1.77 simonb (void)printf("%9u executable pages\n", uvmexp.vtextpages);
569 1.44 mrg
570 1.44 mrg (void)printf("%9u minimum free pages\n", uvmexp.freemin);
571 1.44 mrg (void)printf("%9u target free pages\n", uvmexp.freetarg);
572 1.44 mrg (void)printf("%9u target inactive pages\n", uvmexp.inactarg);
573 1.44 mrg (void)printf("%9u maximum wired pages\n", uvmexp.wiredmax);
574 1.44 mrg
575 1.44 mrg (void)printf("%9u swap devices\n", uvmexp.nswapdev);
576 1.44 mrg (void)printf("%9u swap pages\n", uvmexp.swpages);
577 1.44 mrg (void)printf("%9u swap pages in use\n", uvmexp.swpginuse);
578 1.44 mrg (void)printf("%9u swap allocations\n", uvmexp.nswget);
579 1.44 mrg (void)printf("%9u anons\n", uvmexp.nanon);
580 1.44 mrg (void)printf("%9u free anons\n", uvmexp.nfreeanon);
581 1.44 mrg
582 1.43 mrg (void)printf("%9u total faults taken\n", uvmexp.faults);
583 1.43 mrg (void)printf("%9u traps\n", uvmexp.traps);
584 1.43 mrg (void)printf("%9u device interrupts\n", uvmexp.intrs);
585 1.43 mrg (void)printf("%9u cpu context switches\n", uvmexp.swtch);
586 1.43 mrg (void)printf("%9u software interrupts\n", uvmexp.softs);
587 1.43 mrg (void)printf("%9u system calls\n", uvmexp.syscalls);
588 1.60 fredb (void)printf("%9u pagein requests\n", uvmexp.pageins);
589 1.60 fredb (void)printf("%9u pageout requests\n", uvmexp.pdpageouts);
590 1.43 mrg (void)printf("%9u swap ins\n", uvmexp.swapins);
591 1.43 mrg (void)printf("%9u swap outs\n", uvmexp.swapouts);
592 1.60 fredb (void)printf("%9u pages swapped in\n", uvmexp.pgswapin);
593 1.60 fredb (void)printf("%9u pages swapped out\n", uvmexp.pgswapout);
594 1.43 mrg (void)printf("%9u forks total\n", uvmexp.forks);
595 1.43 mrg (void)printf("%9u forks blocked parent\n", uvmexp.forks_ppwait);
596 1.43 mrg (void)printf("%9u forks shared address space with parent\n",
597 1.43 mrg uvmexp.forks_sharevm);
598 1.63 thorpej (void)printf("%9u pagealloc zero wanted and avail\n",
599 1.63 thorpej uvmexp.pga_zerohit);
600 1.63 thorpej (void)printf("%9u pagealloc zero wanted and not avail\n",
601 1.63 thorpej uvmexp.pga_zeromiss);
602 1.68 thorpej (void)printf("%9u aborts of idle page zeroing\n",
603 1.68 thorpej uvmexp.zeroaborts);
604 1.44 mrg
605 1.44 mrg (void)printf("%9u faults with no memory\n", uvmexp.fltnoram);
606 1.44 mrg (void)printf("%9u faults with no anons\n", uvmexp.fltnoanon);
607 1.43 mrg (void)printf("%9u faults had to wait on pages\n", uvmexp.fltpgwait);
608 1.43 mrg (void)printf("%9u faults found released page\n", uvmexp.fltpgrele);
609 1.43 mrg (void)printf("%9u faults relock (%u ok)\n", uvmexp.fltrelck,
610 1.43 mrg uvmexp.fltrelckok);
611 1.43 mrg (void)printf("%9u anon page faults\n", uvmexp.fltanget);
612 1.43 mrg (void)printf("%9u anon retry faults\n", uvmexp.fltanretry);
613 1.43 mrg (void)printf("%9u amap copy faults\n", uvmexp.fltamcopy);
614 1.43 mrg (void)printf("%9u neighbour anon page faults\n", uvmexp.fltnamap);
615 1.43 mrg (void)printf("%9u neighbour object page faults\n", uvmexp.fltnomap);
616 1.43 mrg (void)printf("%9u locked pager get faults\n", uvmexp.fltlget);
617 1.43 mrg (void)printf("%9u unlocked pager get faults\n", uvmexp.fltget);
618 1.43 mrg (void)printf("%9u anon faults\n", uvmexp.flt_anon);
619 1.43 mrg (void)printf("%9u anon copy on write faults\n", uvmexp.flt_acow);
620 1.43 mrg (void)printf("%9u object faults\n", uvmexp.flt_obj);
621 1.43 mrg (void)printf("%9u promote copy faults\n", uvmexp.flt_prcopy);
622 1.43 mrg (void)printf("%9u promote zero fill faults\n", uvmexp.flt_przero);
623 1.44 mrg
624 1.44 mrg (void)printf("%9u times daemon wokeup\n",uvmexp.pdwoke);
625 1.44 mrg (void)printf("%9u revolutions of the clock hand\n", uvmexp.pdrevs);
626 1.44 mrg (void)printf("%9u times daemon attempted swapout\n", uvmexp.pdswout);
627 1.44 mrg (void)printf("%9u pages freed by daemon\n", uvmexp.pdfreed);
628 1.44 mrg (void)printf("%9u pages scanned by daemon\n", uvmexp.pdscans);
629 1.75 enami (void)printf("%9u anonymous pages scanned by daemon\n",
630 1.75 enami uvmexp.pdanscan);
631 1.44 mrg (void)printf("%9u object pages scanned by daemon\n", uvmexp.pdobscan);
632 1.44 mrg (void)printf("%9u pages reactivated\n", uvmexp.pdreact);
633 1.44 mrg (void)printf("%9u pages found busy by daemon\n", uvmexp.pdbusy);
634 1.44 mrg (void)printf("%9u total pending pageouts\n", uvmexp.pdpending);
635 1.44 mrg (void)printf("%9u pages deactivated\n", uvmexp.pddeact);
636 1.1 cgd kread(X_NCHSTATS, &nchstats, sizeof(nchstats));
637 1.1 cgd nchtotal = nchstats.ncs_goodhits + nchstats.ncs_neghits +
638 1.1 cgd nchstats.ncs_badhits + nchstats.ncs_falsehits +
639 1.1 cgd nchstats.ncs_miss + nchstats.ncs_long;
640 1.1 cgd (void)printf("%9ld total name lookups\n", nchtotal);
641 1.1 cgd (void)printf(
642 1.1 cgd "%9s cache hits (%d%% pos + %d%% neg) system %d%% per-process\n",
643 1.1 cgd "", PCT(nchstats.ncs_goodhits, nchtotal),
644 1.1 cgd PCT(nchstats.ncs_neghits, nchtotal),
645 1.1 cgd PCT(nchstats.ncs_pass2, nchtotal));
646 1.1 cgd (void)printf("%9s deletions %d%%, falsehits %d%%, toolong %d%%\n", "",
647 1.1 cgd PCT(nchstats.ncs_badhits, nchtotal),
648 1.1 cgd PCT(nchstats.ncs_falsehits, nchtotal),
649 1.1 cgd PCT(nchstats.ncs_long, nchtotal));
650 1.1 cgd }
651 1.1 cgd
652 1.1 cgd void
653 1.73 simonb doforkst(void)
654 1.1 cgd {
655 1.41 mrg
656 1.58 thorpej kread(X_UVMEXP, &uvmexp, sizeof(uvmexp));
657 1.58 thorpej
658 1.41 mrg (void)printf("%u forks total\n", uvmexp.forks);
659 1.41 mrg (void)printf("%u forks blocked parent\n", uvmexp.forks_ppwait);
660 1.41 mrg (void)printf("%u forks shared address space with parent\n",
661 1.41 mrg uvmexp.forks_sharevm);
662 1.1 cgd }
663 1.1 cgd
664 1.1 cgd void
665 1.73 simonb dkstats(void)
666 1.1 cgd {
667 1.38 mrg int dn, state;
668 1.1 cgd double etime;
669 1.1 cgd
670 1.29 thorpej /* Calculate disk stat deltas. */
671 1.29 thorpej dkswap();
672 1.1 cgd etime = 0;
673 1.1 cgd for (state = 0; state < CPUSTATES; ++state) {
674 1.29 thorpej etime += cur.cp_time[state];
675 1.1 cgd }
676 1.1 cgd if (etime == 0)
677 1.1 cgd etime = 1;
678 1.1 cgd etime /= hz;
679 1.1 cgd for (dn = 0; dn < dk_ndrive; ++dn) {
680 1.29 thorpej if (!dk_select[dn])
681 1.1 cgd continue;
682 1.29 thorpej (void)printf("%2.0f ", cur.dk_xfer[dn] / etime);
683 1.1 cgd }
684 1.1 cgd }
685 1.1 cgd
686 1.1 cgd void
687 1.73 simonb cpustats(void)
688 1.1 cgd {
689 1.38 mrg int state;
690 1.1 cgd double pct, total;
691 1.1 cgd
692 1.1 cgd total = 0;
693 1.1 cgd for (state = 0; state < CPUSTATES; ++state)
694 1.29 thorpej total += cur.cp_time[state];
695 1.1 cgd if (total)
696 1.1 cgd pct = 100 / total;
697 1.1 cgd else
698 1.1 cgd pct = 0;
699 1.75 enami (void)printf("%2.0f ",
700 1.75 enami (cur.cp_time[CP_USER] + cur.cp_time[CP_NICE]) * pct);
701 1.75 enami (void)printf("%2.0f ",
702 1.75 enami (cur.cp_time[CP_SYS] + cur.cp_time[CP_INTR]) * pct);
703 1.29 thorpej (void)printf("%2.0f", cur.cp_time[CP_IDLE] * pct);
704 1.1 cgd }
705 1.1 cgd
706 1.23 phil #if defined(pc532)
707 1.24 phil /* To get struct iv ...*/
708 1.75 enami #define _KERNEL
709 1.23 phil #include <machine/psl.h>
710 1.24 phil #undef _KERNEL
711 1.23 phil void
712 1.66 cgd dointr(int verbose)
713 1.23 phil {
714 1.38 mrg long i, j, inttotal, uptime;
715 1.23 phil static char iname[64];
716 1.23 phil struct iv ivt[32], *ivp = ivt;
717 1.23 phil
718 1.23 phil iname[63] = '\0';
719 1.23 phil uptime = getuptime();
720 1.23 phil kread(X_IVT, ivp, sizeof(ivt));
721 1.23 phil
722 1.23 phil for (i = 0; i < 2; i++) {
723 1.23 phil (void)printf("%sware interrupts:\n", i ? "\nsoft" : "hard");
724 1.23 phil (void)printf("interrupt total rate\n");
725 1.23 phil inttotal = 0;
726 1.23 phil for (j = 0; j < 16; j++, ivp++) {
727 1.66 cgd if (ivp->iv_vec && ivp->iv_use &&
728 1.66 cgd (ivp->iv_cnt || verbose)) {
729 1.75 enami if (kvm_read(kd, (u_long)ivp->iv_use, iname,
730 1.75 enami 63) != 63) {
731 1.75 enami (void)fprintf(stderr,
732 1.75 enami "vmstat: iv_use: %s\n",
733 1.23 phil kvm_geterr(kd));
734 1.23 phil exit(1);
735 1.23 phil }
736 1.23 phil (void)printf("%-12s %8ld %8ld\n", iname,
737 1.23 phil ivp->iv_cnt, ivp->iv_cnt / uptime);
738 1.23 phil inttotal += ivp->iv_cnt;
739 1.23 phil }
740 1.23 phil }
741 1.23 phil (void)printf("Total %8ld %8ld\n",
742 1.23 phil inttotal, inttotal / uptime);
743 1.23 phil }
744 1.23 phil }
745 1.23 phil #else
746 1.1 cgd void
747 1.66 cgd dointr(int verbose)
748 1.1 cgd {
749 1.66 cgd long *intrcnt;
750 1.66 cgd long long inttotal, uptime;
751 1.38 mrg int nintr, inamlen;
752 1.38 mrg char *intrname;
753 1.28 cgd struct evcntlist allevents;
754 1.28 cgd struct evcnt evcnt, *evptr;
755 1.66 cgd char evgroup[EVCNT_STRING_MAX], evname[EVCNT_STRING_MAX];
756 1.1 cgd
757 1.1 cgd uptime = getuptime();
758 1.13 cgd nintr = namelist[X_EINTRCNT].n_value - namelist[X_INTRCNT].n_value;
759 1.13 cgd inamlen =
760 1.13 cgd namelist[X_EINTRNAMES].n_value - namelist[X_INTRNAMES].n_value;
761 1.1 cgd intrcnt = malloc((size_t)nintr);
762 1.1 cgd intrname = malloc((size_t)inamlen);
763 1.1 cgd if (intrcnt == NULL || intrname == NULL) {
764 1.1 cgd (void)fprintf(stderr, "vmstat: %s.\n", strerror(errno));
765 1.1 cgd exit(1);
766 1.1 cgd }
767 1.1 cgd kread(X_INTRCNT, intrcnt, (size_t)nintr);
768 1.1 cgd kread(X_INTRNAMES, intrname, (size_t)inamlen);
769 1.66 cgd (void)printf("%-24s %16s %8s\n", "interrupt", "total", "rate");
770 1.1 cgd inttotal = 0;
771 1.1 cgd nintr /= sizeof(long);
772 1.1 cgd while (--nintr >= 0) {
773 1.66 cgd if (*intrcnt || verbose)
774 1.66 cgd (void)printf("%-24s %16lld %8lld\n", intrname,
775 1.66 cgd (long long)*intrcnt,
776 1.66 cgd (long long)(*intrcnt / uptime));
777 1.1 cgd intrname += strlen(intrname) + 1;
778 1.1 cgd inttotal += *intrcnt++;
779 1.1 cgd }
780 1.18 pk kread(X_ALLEVENTS, &allevents, sizeof allevents);
781 1.28 cgd evptr = allevents.tqh_first;
782 1.28 cgd while (evptr) {
783 1.75 enami if (kvm_read(kd, (long)evptr, &evcnt, sizeof evcnt) !=
784 1.75 enami sizeof(evcnt)) {
785 1.66 cgd event_chain_trashed:
786 1.75 enami (void)fprintf(stderr,
787 1.75 enami "vmstat: event chain trashed: %s\n",
788 1.18 pk kvm_geterr(kd));
789 1.18 pk exit(1);
790 1.18 pk }
791 1.66 cgd
792 1.66 cgd evptr = evcnt.ev_list.tqe_next;
793 1.66 cgd if (evcnt.ev_type != EVCNT_TYPE_INTR)
794 1.66 cgd continue;
795 1.66 cgd
796 1.66 cgd if (evcnt.ev_count == 0 && !verbose)
797 1.66 cgd continue;
798 1.66 cgd
799 1.66 cgd if (kvm_read(kd, (long)evcnt.ev_group, evgroup,
800 1.66 cgd evcnt.ev_grouplen + 1) != evcnt.ev_grouplen + 1)
801 1.66 cgd goto event_chain_trashed;
802 1.66 cgd if (kvm_read(kd, (long)evcnt.ev_name, evname,
803 1.66 cgd evcnt.ev_namelen + 1) != evcnt.ev_namelen + 1)
804 1.66 cgd goto event_chain_trashed;
805 1.66 cgd
806 1.66 cgd (void)printf("%s %s%*s %16lld %8lld\n", evgroup, evname,
807 1.66 cgd 24 - (evcnt.ev_grouplen + 1 + evcnt.ev_namelen), "",
808 1.66 cgd (long long)evcnt.ev_count,
809 1.66 cgd (long long)(evcnt.ev_count / uptime));
810 1.66 cgd
811 1.66 cgd inttotal += evcnt.ev_count++;
812 1.66 cgd }
813 1.66 cgd (void)printf("%-24s %16lld %8lld\n", "Total", inttotal,
814 1.66 cgd (long long)(inttotal / uptime));
815 1.66 cgd }
816 1.66 cgd #endif
817 1.66 cgd
818 1.66 cgd void
819 1.66 cgd doevcnt(int verbose)
820 1.66 cgd {
821 1.66 cgd long long uptime;
822 1.66 cgd struct evcntlist allevents;
823 1.66 cgd struct evcnt evcnt, *evptr;
824 1.66 cgd char evgroup[EVCNT_STRING_MAX], evname[EVCNT_STRING_MAX];
825 1.66 cgd
826 1.66 cgd /* XXX should print type! */
827 1.66 cgd
828 1.66 cgd uptime = getuptime();
829 1.66 cgd (void)printf("%-24s %16s %8s %s\n", "event", "total", "rate", "type");
830 1.66 cgd kread(X_ALLEVENTS, &allevents, sizeof allevents);
831 1.66 cgd evptr = allevents.tqh_first;
832 1.66 cgd while (evptr) {
833 1.75 enami if (kvm_read(kd, (long)evptr, &evcnt, sizeof evcnt) !=
834 1.75 enami sizeof(evcnt)) {
835 1.66 cgd event_chain_trashed:
836 1.75 enami (void)fprintf(stderr,
837 1.75 enami "vmstat: event chain trashed: %s\n",
838 1.32 cgd kvm_geterr(kd));
839 1.32 cgd exit(1);
840 1.18 pk }
841 1.32 cgd
842 1.28 cgd evptr = evcnt.ev_list.tqe_next;
843 1.66 cgd if (evcnt.ev_count == 0 && !verbose)
844 1.66 cgd continue;
845 1.66 cgd
846 1.66 cgd if (kvm_read(kd, (long)evcnt.ev_group, evgroup,
847 1.66 cgd evcnt.ev_grouplen + 1) != evcnt.ev_grouplen + 1)
848 1.66 cgd goto event_chain_trashed;
849 1.66 cgd if (kvm_read(kd, (long)evcnt.ev_name, evname,
850 1.66 cgd evcnt.ev_namelen + 1) != evcnt.ev_namelen + 1)
851 1.66 cgd goto event_chain_trashed;
852 1.66 cgd
853 1.66 cgd (void)printf("%s %s%*s %16lld %8lld %s\n", evgroup, evname,
854 1.66 cgd 24 - (evcnt.ev_grouplen + 1 + evcnt.ev_namelen), "",
855 1.66 cgd (long long)evcnt.ev_count,
856 1.66 cgd (long long)(evcnt.ev_count / uptime),
857 1.66 cgd /* XXX do the following with an array lookup XXX */
858 1.66 cgd (evcnt.ev_type == EVCNT_TYPE_MISC) ? "misc" :
859 1.75 enami ((evcnt.ev_type == EVCNT_TYPE_INTR) ? "intr" : "?"));
860 1.18 pk }
861 1.1 cgd }
862 1.1 cgd
863 1.1 cgd /*
864 1.1 cgd * These names are defined in <sys/malloc.h>.
865 1.1 cgd */
866 1.1 cgd char *kmemnames[] = INITKMEMNAMES;
867 1.1 cgd
868 1.1 cgd void
869 1.73 simonb domem(void)
870 1.1 cgd {
871 1.38 mrg struct kmembuckets *kp;
872 1.38 mrg struct kmemstats *ks;
873 1.38 mrg int i, j;
874 1.13 cgd int len, size, first;
875 1.13 cgd long totuse = 0, totfree = 0, totreq = 0;
876 1.13 cgd char *name;
877 1.13 cgd struct kmemstats kmemstats[M_LAST];
878 1.1 cgd struct kmembuckets buckets[MINBUCKET + 16];
879 1.1 cgd
880 1.1 cgd kread(X_KMEMBUCKETS, buckets, sizeof(buckets));
881 1.34 thorpej for (first = 1, i = MINBUCKET, kp = &buckets[i]; i < MINBUCKET + 16;
882 1.34 thorpej i++, kp++) {
883 1.1 cgd if (kp->kb_calls == 0)
884 1.1 cgd continue;
885 1.34 thorpej if (first) {
886 1.34 thorpej (void)printf("Memory statistics by bucket size\n");
887 1.34 thorpej (void)printf(
888 1.34 thorpej " Size In Use Free Requests HighWater Couldfree\n");
889 1.34 thorpej first = 0;
890 1.34 thorpej }
891 1.1 cgd size = 1 << i;
892 1.75 enami (void)printf("%8d %8ld %6ld %10ld %7ld %10ld\n", size,
893 1.75 enami kp->kb_total - kp->kb_totalfree,
894 1.75 enami kp->kb_totalfree, kp->kb_calls,
895 1.75 enami kp->kb_highwat, kp->kb_couldfree);
896 1.1 cgd totfree += size * kp->kb_totalfree;
897 1.34 thorpej }
898 1.34 thorpej
899 1.34 thorpej /*
900 1.34 thorpej * If kmem statistics are not being gathered by the kernel,
901 1.34 thorpej * first will still be 1.
902 1.34 thorpej */
903 1.34 thorpej if (first) {
904 1.34 thorpej printf(
905 1.34 thorpej "Kmem statistics are not being gathered by the kernel.\n");
906 1.34 thorpej return;
907 1.1 cgd }
908 1.1 cgd
909 1.1 cgd kread(X_KMEMSTAT, kmemstats, sizeof(kmemstats));
910 1.13 cgd (void)printf("\nMemory usage type by bucket size\n");
911 1.13 cgd (void)printf(" Size Type(s)\n");
912 1.13 cgd kp = &buckets[MINBUCKET];
913 1.13 cgd for (j = 1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1, kp++) {
914 1.13 cgd if (kp->kb_calls == 0)
915 1.13 cgd continue;
916 1.13 cgd first = 1;
917 1.13 cgd len = 8;
918 1.13 cgd for (i = 0, ks = &kmemstats[0]; i < M_LAST; i++, ks++) {
919 1.13 cgd if (ks->ks_calls == 0)
920 1.13 cgd continue;
921 1.13 cgd if ((ks->ks_size & j) == 0)
922 1.13 cgd continue;
923 1.35 is if (kmemnames[i] == 0) {
924 1.35 is kmemnames[i] = malloc(10);
925 1.35 is /* strlen("undef/")+3+1);*/
926 1.35 is snprintf(kmemnames[i], 10, "undef/%d", i);
927 1.35 is /* same 10 as above!!! */
928 1.35 is }
929 1.35 is name = kmemnames[i];
930 1.13 cgd len += 2 + strlen(name);
931 1.13 cgd if (first)
932 1.13 cgd printf("%8d %s", j, name);
933 1.13 cgd else
934 1.13 cgd printf(",");
935 1.13 cgd if (len >= 80) {
936 1.13 cgd printf("\n\t ");
937 1.13 cgd len = 10 + strlen(name);
938 1.13 cgd }
939 1.13 cgd if (!first)
940 1.13 cgd printf(" %s", name);
941 1.13 cgd first = 0;
942 1.13 cgd }
943 1.13 cgd printf("\n");
944 1.13 cgd }
945 1.13 cgd
946 1.1 cgd (void)printf(
947 1.13 cgd "\nMemory statistics by type Type Kern\n");
948 1.13 cgd (void)printf(
949 1.36 is " Type InUse MemUse HighUse Limit Requests Limit Limit Size(s)\n");
950 1.13 cgd for (i = 0, ks = &kmemstats[0]; i < M_LAST; i++, ks++) {
951 1.1 cgd if (ks->ks_calls == 0)
952 1.1 cgd continue;
953 1.36 is (void)printf("%14s%6ld%6ldK%7ldK%6ldK%9ld%5u%6u",
954 1.1 cgd kmemnames[i] ? kmemnames[i] : "undefined",
955 1.1 cgd ks->ks_inuse, (ks->ks_memuse + 1023) / 1024,
956 1.1 cgd (ks->ks_maxused + 1023) / 1024,
957 1.1 cgd (ks->ks_limit + 1023) / 1024, ks->ks_calls,
958 1.1 cgd ks->ks_limblocks, ks->ks_mapblocks);
959 1.13 cgd first = 1;
960 1.13 cgd for (j = 1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1) {
961 1.13 cgd if ((ks->ks_size & j) == 0)
962 1.13 cgd continue;
963 1.13 cgd if (first)
964 1.13 cgd printf(" %d", j);
965 1.13 cgd else
966 1.13 cgd printf(",%d", j);
967 1.13 cgd first = 0;
968 1.13 cgd }
969 1.13 cgd printf("\n");
970 1.1 cgd totuse += ks->ks_memuse;
971 1.1 cgd totreq += ks->ks_calls;
972 1.1 cgd }
973 1.13 cgd (void)printf("\nMemory Totals: In Use Free Requests\n");
974 1.13 cgd (void)printf(" %7ldK %6ldK %8ld\n",
975 1.75 enami (totuse + 1023) / 1024, (totfree + 1023) / 1024, totreq);
976 1.51 pk }
977 1.51 pk
978 1.51 pk void
979 1.73 simonb dopool(void)
980 1.51 pk {
981 1.69 enami int first, ovflw;
982 1.51 pk long addr;
983 1.51 pk long total = 0, inuse = 0;
984 1.51 pk TAILQ_HEAD(,pool) pool_head;
985 1.51 pk struct pool pool, *pp = &pool;
986 1.51 pk
987 1.51 pk kread(X_POOLHEAD, &pool_head, sizeof(pool_head));
988 1.51 pk addr = (long)TAILQ_FIRST(&pool_head);
989 1.51 pk
990 1.51 pk for (first = 1; addr != 0; ) {
991 1.51 pk char name[32], maxp[32];
992 1.51 pk if (kvm_read(kd, addr, (void *)pp, sizeof *pp) != sizeof *pp) {
993 1.75 enami (void)fprintf(stderr,
994 1.75 enami "vmstat: pool chain trashed: %s\n",
995 1.51 pk kvm_geterr(kd));
996 1.51 pk exit(1);
997 1.51 pk }
998 1.51 pk if (kvm_read(kd, (long)pp->pr_wchan, name, sizeof name) < 0) {
999 1.75 enami (void)fprintf(stderr,
1000 1.75 enami "vmstat: pool name trashed: %s\n",
1001 1.51 pk kvm_geterr(kd));
1002 1.51 pk exit(1);
1003 1.51 pk }
1004 1.75 enami name[31] = '\0';
1005 1.51 pk
1006 1.51 pk if (first) {
1007 1.51 pk (void)printf("Memory resource pool statistics\n");
1008 1.51 pk (void)printf(
1009 1.75 enami "%-11s%5s%9s%5s%9s%6s%6s%6s%6s%6s%6s%5s\n",
1010 1.75 enami "Name",
1011 1.75 enami "Size",
1012 1.75 enami "Requests",
1013 1.75 enami "Fail",
1014 1.75 enami "Releases",
1015 1.75 enami "Pgreq",
1016 1.75 enami "Pgrel",
1017 1.75 enami "Npage",
1018 1.75 enami "Hiwat",
1019 1.75 enami "Minpg",
1020 1.75 enami "Maxpg",
1021 1.75 enami "Idle");
1022 1.51 pk first = 0;
1023 1.51 pk }
1024 1.51 pk if (pp->pr_maxpages == UINT_MAX)
1025 1.51 pk sprintf(maxp, "inf");
1026 1.51 pk else
1027 1.69 enami sprintf(maxp, "%u", pp->pr_maxpages);
1028 1.69 enami /*
1029 1.69 enami * Print single word. `ovflow' is number of characters didn't fit
1030 1.69 enami * on the last word. `fmt' is a format string to print this word.
1031 1.69 enami * It must contain asterisk for field width. `width' is a width
1032 1.69 enami * occupied by this word. `fixed' is a number of constant chars in
1033 1.69 enami * `fmt'. `val' is a value to be printed using format string `fmt'.
1034 1.69 enami */
1035 1.69 enami #define PRWORD(ovflw, fmt, width, fixed, val) do { \
1036 1.69 enami (ovflw) += printf((fmt), \
1037 1.69 enami (width) - (fixed) - (ovflw) > 0 ? \
1038 1.69 enami (width) - (fixed) - (ovflw) : 0, \
1039 1.69 enami (val)) - (width); \
1040 1.69 enami if ((ovflw) < 0) \
1041 1.69 enami (ovflw) = 0; \
1042 1.69 enami } while (/* CONSTCOND */0)
1043 1.69 enami ovflw = 0;
1044 1.69 enami PRWORD(ovflw, "%-*s", 11, 0, name);
1045 1.69 enami PRWORD(ovflw, " %*u", 5, 1, pp->pr_size);
1046 1.69 enami PRWORD(ovflw, " %*lu", 9, 1, pp->pr_nget);
1047 1.69 enami PRWORD(ovflw, " %*lu", 5, 1, pp->pr_nfail);
1048 1.69 enami PRWORD(ovflw, " %*lu", 9, 1, pp->pr_nput);
1049 1.69 enami PRWORD(ovflw, " %*lu", 6, 1, pp->pr_npagealloc);
1050 1.69 enami PRWORD(ovflw, " %*lu", 6, 1, pp->pr_npagefree);
1051 1.69 enami PRWORD(ovflw, " %*d", 6, 1, pp->pr_npages);
1052 1.69 enami PRWORD(ovflw, " %*d", 6, 1, pp->pr_hiwat);
1053 1.69 enami PRWORD(ovflw, " %*d", 6, 1, pp->pr_minpages);
1054 1.69 enami PRWORD(ovflw, " %*s", 6, 1, maxp);
1055 1.69 enami PRWORD(ovflw, " %*lu\n", 5, 1, pp->pr_nidle);
1056 1.51 pk
1057 1.51 pk inuse += (pp->pr_nget - pp->pr_nput) * pp->pr_size;
1058 1.51 pk total += pp->pr_npages * pp->pr_pagesz;
1059 1.51 pk addr = (long)TAILQ_NEXT(pp, pr_poollist);
1060 1.51 pk }
1061 1.51 pk
1062 1.76 enami inuse /= 1024;
1063 1.76 enami total /= 1024;
1064 1.51 pk printf("\nIn use %ldK, total allocated %ldK; utilization %.1f%%\n",
1065 1.76 enami inuse, total, (double)(100 * inuse) / total);
1066 1.1 cgd }
1067 1.1 cgd
1068 1.1 cgd /*
1069 1.1 cgd * kread reads something from the kernel, given its nlist index.
1070 1.1 cgd */
1071 1.1 cgd void
1072 1.73 simonb kread(int nlx, void *addr, size_t size)
1073 1.1 cgd {
1074 1.50 mycroft const char *sym;
1075 1.1 cgd
1076 1.13 cgd if (namelist[nlx].n_type == 0 || namelist[nlx].n_value == 0) {
1077 1.13 cgd sym = namelist[nlx].n_name;
1078 1.1 cgd if (*sym == '_')
1079 1.1 cgd ++sym;
1080 1.1 cgd (void)fprintf(stderr,
1081 1.13 cgd "vmstat: symbol %s not defined\n", sym);
1082 1.1 cgd exit(1);
1083 1.1 cgd }
1084 1.13 cgd if (kvm_read(kd, namelist[nlx].n_value, addr, size) != size) {
1085 1.13 cgd sym = namelist[nlx].n_name;
1086 1.1 cgd if (*sym == '_')
1087 1.1 cgd ++sym;
1088 1.13 cgd (void)fprintf(stderr, "vmstat: %s: %s\n", sym, kvm_geterr(kd));
1089 1.1 cgd exit(1);
1090 1.1 cgd }
1091 1.1 cgd }
1092 1.1 cgd
1093 1.45 thorpej struct nlist histnl[] = {
1094 1.45 thorpej { "_uvm_histories" },
1095 1.45 thorpej #define X_UVM_HISTORIES 0
1096 1.45 thorpej { NULL },
1097 1.45 thorpej };
1098 1.45 thorpej
1099 1.45 thorpej /*
1100 1.45 thorpej * Traverse the UVM history buffers, performing the requested action.
1101 1.45 thorpej *
1102 1.45 thorpej * Note, we assume that if we're not listing, we're dumping.
1103 1.45 thorpej */
1104 1.45 thorpej void
1105 1.73 simonb hist_traverse(int todo, const char *histname)
1106 1.45 thorpej {
1107 1.45 thorpej struct uvm_history_head histhead;
1108 1.45 thorpej struct uvm_history hist, *histkva;
1109 1.45 thorpej char *name = NULL;
1110 1.45 thorpej size_t namelen = 0;
1111 1.45 thorpej
1112 1.45 thorpej if (kvm_nlist(kd, histnl) != 0) {
1113 1.45 thorpej printf("UVM history is not compiled into the kernel.\n");
1114 1.45 thorpej return;
1115 1.45 thorpej }
1116 1.45 thorpej
1117 1.45 thorpej if (kvm_read(kd, histnl[X_UVM_HISTORIES].n_value, &histhead,
1118 1.45 thorpej sizeof(histhead)) != sizeof(histhead)) {
1119 1.45 thorpej warnx("unable to read %s: %s",
1120 1.45 thorpej histnl[X_UVM_HISTORIES].n_name, kvm_geterr(kd));
1121 1.45 thorpej return;
1122 1.45 thorpej }
1123 1.45 thorpej
1124 1.45 thorpej if (histhead.lh_first == NULL) {
1125 1.45 thorpej printf("No active UVM history logs.\n");
1126 1.45 thorpej return;
1127 1.45 thorpej }
1128 1.45 thorpej
1129 1.45 thorpej if (todo & HISTLIST)
1130 1.45 thorpej printf("Active UVM histories:");
1131 1.45 thorpej
1132 1.75 enami for (histkva = LIST_FIRST(&histhead); histkva != NULL;
1133 1.75 enami histkva = LIST_NEXT(&hist, list)) {
1134 1.45 thorpej if (kvm_read(kd, (u_long)histkva, &hist, sizeof(hist)) !=
1135 1.45 thorpej sizeof(hist)) {
1136 1.45 thorpej warnx("unable to read history at %p: %s",
1137 1.45 thorpej histkva, kvm_geterr(kd));
1138 1.45 thorpej goto out;
1139 1.45 thorpej }
1140 1.45 thorpej
1141 1.45 thorpej if (hist.namelen > namelen) {
1142 1.45 thorpej if (name != NULL)
1143 1.45 thorpej free(name);
1144 1.45 thorpej namelen = hist.namelen;
1145 1.45 thorpej if ((name = malloc(namelen + 1)) == NULL)
1146 1.45 thorpej err(1, "malloc history name");
1147 1.45 thorpej }
1148 1.45 thorpej
1149 1.45 thorpej if (kvm_read(kd, (u_long)hist.name, name, namelen) !=
1150 1.45 thorpej namelen) {
1151 1.45 thorpej warnx("unable to read history name at %p: %s",
1152 1.45 thorpej hist.name, kvm_geterr(kd));
1153 1.45 thorpej goto out;
1154 1.45 thorpej }
1155 1.45 thorpej name[namelen] = '\0';
1156 1.45 thorpej if (todo & HISTLIST)
1157 1.45 thorpej printf(" %s", name);
1158 1.45 thorpej else {
1159 1.45 thorpej /*
1160 1.45 thorpej * If we're dumping all histories, do it, else
1161 1.45 thorpej * check to see if this is the one we want.
1162 1.45 thorpej */
1163 1.45 thorpej if (histname == NULL || strcmp(histname, name) == 0) {
1164 1.45 thorpej if (histname == NULL)
1165 1.45 thorpej printf("\nUVM history `%s':\n", name);
1166 1.45 thorpej hist_dodump(&hist);
1167 1.45 thorpej }
1168 1.45 thorpej }
1169 1.45 thorpej }
1170 1.45 thorpej
1171 1.45 thorpej if (todo & HISTLIST)
1172 1.45 thorpej printf("\n");
1173 1.45 thorpej
1174 1.45 thorpej out:
1175 1.45 thorpej if (name != NULL)
1176 1.45 thorpej free(name);
1177 1.45 thorpej }
1178 1.45 thorpej
1179 1.45 thorpej /*
1180 1.45 thorpej * Actually dump the history buffer at the specified KVA.
1181 1.45 thorpej */
1182 1.45 thorpej void
1183 1.73 simonb hist_dodump(struct uvm_history *histp)
1184 1.45 thorpej {
1185 1.45 thorpej struct uvm_history_ent *histents, *e;
1186 1.45 thorpej size_t histsize;
1187 1.45 thorpej char *fmt = NULL, *fn = NULL;
1188 1.45 thorpej size_t fmtlen = 0, fnlen = 0;
1189 1.45 thorpej int i;
1190 1.45 thorpej
1191 1.45 thorpej histsize = sizeof(struct uvm_history_ent) * histp->n;
1192 1.45 thorpej
1193 1.45 thorpej if ((histents = malloc(histsize)) == NULL)
1194 1.45 thorpej err(1, "malloc history entries");
1195 1.45 thorpej
1196 1.45 thorpej memset(histents, 0, histsize);
1197 1.45 thorpej
1198 1.45 thorpej if (kvm_read(kd, (u_long)histp->e, histents, histsize) != histsize) {
1199 1.45 thorpej warnx("unable to read history entries at %p: %s",
1200 1.45 thorpej histp->e, kvm_geterr(kd));
1201 1.45 thorpej goto out;
1202 1.45 thorpej }
1203 1.45 thorpej
1204 1.45 thorpej i = histp->f;
1205 1.45 thorpej do {
1206 1.45 thorpej e = &histents[i];
1207 1.45 thorpej if (e->fmt != NULL) {
1208 1.45 thorpej if (e->fmtlen > fmtlen) {
1209 1.45 thorpej if (fmt != NULL)
1210 1.45 thorpej free(fmt);
1211 1.45 thorpej fmtlen = e->fmtlen;
1212 1.45 thorpej if ((fmt = malloc(fmtlen + 1)) == NULL)
1213 1.45 thorpej err(1, "malloc printf format");
1214 1.45 thorpej }
1215 1.45 thorpej if (e->fnlen > fnlen) {
1216 1.45 thorpej if (fn != NULL)
1217 1.45 thorpej free(fn);
1218 1.45 thorpej fnlen = e->fnlen;
1219 1.45 thorpej if ((fn = malloc(fnlen + 1)) == NULL)
1220 1.45 thorpej err(1, "malloc function name");
1221 1.45 thorpej }
1222 1.45 thorpej
1223 1.75 enami if (kvm_read(kd, (u_long)e->fmt, fmt, fmtlen) !=
1224 1.75 enami fmtlen) {
1225 1.45 thorpej warnx("unable to read printf format "
1226 1.45 thorpej "at %p: %s", e->fmt, kvm_geterr(kd));
1227 1.45 thorpej goto out;
1228 1.45 thorpej }
1229 1.45 thorpej fmt[fmtlen] = '\0';
1230 1.45 thorpej
1231 1.45 thorpej if (kvm_read(kd, (u_long)e->fn, fn, fnlen) != fnlen) {
1232 1.45 thorpej warnx("unable to read function name "
1233 1.45 thorpej "at %p: %s", e->fn, kvm_geterr(kd));
1234 1.45 thorpej goto out;
1235 1.45 thorpej }
1236 1.45 thorpej fn[fnlen] = '\0';
1237 1.45 thorpej
1238 1.61 kleink printf("%06ld.%06ld ", (long int)e->tv.tv_sec,
1239 1.61 kleink (long int)e->tv.tv_usec);
1240 1.75 enami printf("%s#%ld: ", fn, e->call);
1241 1.45 thorpej printf(fmt, e->v[0], e->v[1], e->v[2], e->v[3]);
1242 1.45 thorpej printf("\n");
1243 1.45 thorpej }
1244 1.45 thorpej i = (i + 1) % histp->n;
1245 1.45 thorpej } while (i != histp->f);
1246 1.45 thorpej
1247 1.45 thorpej out:
1248 1.45 thorpej free(histents);
1249 1.45 thorpej if (fmt != NULL)
1250 1.45 thorpej free(fmt);
1251 1.45 thorpej if (fn != NULL)
1252 1.45 thorpej free(fn);
1253 1.45 thorpej }
1254 1.45 thorpej
1255 1.1 cgd void
1256 1.73 simonb usage(void)
1257 1.1 cgd {
1258 1.47 mrg
1259 1.1 cgd (void)fprintf(stderr,
1260 1.75 enami "usage: vmstat [-efHilmsv] [-h histname] [-c count] [-M core] "
1261 1.75 enami "[-N system] [-w wait] [disks]\n");
1262 1.1 cgd exit(1);
1263 1.1 cgd }
1264