vmstat.c revision 1.155 1 1.155 yamt /* $NetBSD: vmstat.c,v 1.155 2007/12/05 09:20:56 yamt Exp $ */
2 1.45 thorpej
3 1.45 thorpej /*-
4 1.154 ad * Copyright (c) 1998, 2000, 2001, 2007 The NetBSD Foundation, Inc.
5 1.45 thorpej * All rights reserved.
6 1.45 thorpej *
7 1.87 lukem * This code is derived from software contributed to The NetBSD Foundation by:
8 1.87 lukem * - Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 1.87 lukem * NASA Ames Research Center.
10 1.87 lukem * - Simon Burge and Luke Mewburn of Wasabi Systems, Inc.
11 1.45 thorpej *
12 1.45 thorpej * Redistribution and use in source and binary forms, with or without
13 1.45 thorpej * modification, are permitted provided that the following conditions
14 1.45 thorpej * are met:
15 1.45 thorpej * 1. Redistributions of source code must retain the above copyright
16 1.45 thorpej * notice, this list of conditions and the following disclaimer.
17 1.45 thorpej * 2. Redistributions in binary form must reproduce the above copyright
18 1.45 thorpej * notice, this list of conditions and the following disclaimer in the
19 1.45 thorpej * documentation and/or other materials provided with the distribution.
20 1.45 thorpej * 3. All advertising materials mentioning features or use of this software
21 1.45 thorpej * must display the following acknowledgement:
22 1.45 thorpej * This product includes software developed by the NetBSD
23 1.45 thorpej * Foundation, Inc. and its contributors.
24 1.45 thorpej * 4. Neither the name of The NetBSD Foundation nor the names of its
25 1.45 thorpej * contributors may be used to endorse or promote products derived
26 1.45 thorpej * from this software without specific prior written permission.
27 1.45 thorpej *
28 1.45 thorpej * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
29 1.45 thorpej * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
30 1.45 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
31 1.45 thorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
32 1.45 thorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
33 1.45 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
34 1.45 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
35 1.45 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
36 1.45 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
37 1.45 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
38 1.45 thorpej * POSSIBILITY OF SUCH DAMAGE.
39 1.45 thorpej */
40 1.21 cgd
41 1.1 cgd /*
42 1.13 cgd * Copyright (c) 1980, 1986, 1991, 1993
43 1.13 cgd * The Regents of the University of California. All rights reserved.
44 1.1 cgd *
45 1.1 cgd * Redistribution and use in source and binary forms, with or without
46 1.1 cgd * modification, are permitted provided that the following conditions
47 1.1 cgd * are met:
48 1.1 cgd * 1. Redistributions of source code must retain the above copyright
49 1.1 cgd * notice, this list of conditions and the following disclaimer.
50 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
51 1.1 cgd * notice, this list of conditions and the following disclaimer in the
52 1.1 cgd * documentation and/or other materials provided with the distribution.
53 1.117 agc * 3. Neither the name of the University nor the names of its contributors
54 1.1 cgd * may be used to endorse or promote products derived from this software
55 1.1 cgd * without specific prior written permission.
56 1.1 cgd *
57 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
58 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
59 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
60 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
61 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
62 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
63 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
64 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
65 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
66 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
67 1.1 cgd * SUCH DAMAGE.
68 1.1 cgd */
69 1.1 cgd
70 1.38 mrg #include <sys/cdefs.h>
71 1.1 cgd #ifndef lint
72 1.38 mrg __COPYRIGHT("@(#) Copyright (c) 1980, 1986, 1991, 1993\n\
73 1.38 mrg The Regents of the University of California. All rights reserved.\n");
74 1.1 cgd #endif /* not lint */
75 1.1 cgd
76 1.1 cgd #ifndef lint
77 1.21 cgd #if 0
78 1.37 mrg static char sccsid[] = "@(#)vmstat.c 8.2 (Berkeley) 3/1/95";
79 1.21 cgd #else
80 1.155 yamt __RCSID("$NetBSD: vmstat.c,v 1.155 2007/12/05 09:20:56 yamt Exp $");
81 1.21 cgd #endif
82 1.1 cgd #endif /* not lint */
83 1.57 thorpej
84 1.57 thorpej #define __POOL_EXPOSE
85 1.1 cgd
86 1.1 cgd #include <sys/param.h>
87 1.87 lukem #include <sys/mount.h>
88 1.87 lukem #include <sys/uio.h>
89 1.87 lukem
90 1.87 lukem #include <sys/buf.h>
91 1.146 yamt #include <sys/evcnt.h>
92 1.87 lukem #include <sys/ioctl.h>
93 1.87 lukem #include <sys/malloc.h>
94 1.109 thorpej #include <sys/mallocvar.h>
95 1.1 cgd #include <sys/namei.h>
96 1.87 lukem #include <sys/pool.h>
97 1.87 lukem #include <sys/proc.h>
98 1.64 perry #include <sys/sched.h>
99 1.87 lukem #include <sys/socket.h>
100 1.13 cgd #include <sys/sysctl.h>
101 1.87 lukem #include <sys/time.h>
102 1.87 lukem #include <sys/user.h>
103 1.67 mrg
104 1.67 mrg #include <uvm/uvm_extern.h>
105 1.67 mrg #include <uvm/uvm_stat.h>
106 1.67 mrg
107 1.87 lukem #include <net/if.h>
108 1.87 lukem #include <netinet/in.h>
109 1.87 lukem #include <netinet/in_var.h>
110 1.87 lukem
111 1.87 lukem #include <ufs/ufs/inode.h>
112 1.87 lukem
113 1.87 lukem #include <nfs/rpcv2.h>
114 1.87 lukem #include <nfs/nfsproto.h>
115 1.87 lukem #include <nfs/nfsnode.h>
116 1.87 lukem
117 1.87 lukem #include <ctype.h>
118 1.45 thorpej #include <err.h>
119 1.87 lukem #include <errno.h>
120 1.55 kleink #include <fcntl.h>
121 1.87 lukem #include <kvm.h>
122 1.87 lukem #include <limits.h>
123 1.1 cgd #include <nlist.h>
124 1.87 lukem #undef n_hash
125 1.87 lukem #include <paths.h>
126 1.22 jtc #include <signal.h>
127 1.1 cgd #include <stdio.h>
128 1.87 lukem #include <stddef.h>
129 1.1 cgd #include <stdlib.h>
130 1.1 cgd #include <string.h>
131 1.87 lukem #include <time.h>
132 1.87 lukem #include <unistd.h>
133 1.104 mrg #include <util.h>
134 1.87 lukem
135 1.140 blymn #include "drvstats.h"
136 1.45 thorpej
137 1.90 lukem /*
138 1.90 lukem * General namelist
139 1.90 lukem */
140 1.87 lukem struct nlist namelist[] =
141 1.87 lukem {
142 1.65 itojun #define X_BOOTTIME 0
143 1.153 christos { .n_name = "_boottime" },
144 1.75 enami #define X_HZ 1
145 1.153 christos { .n_name = "_hz" },
146 1.75 enami #define X_STATHZ 2
147 1.153 christos { .n_name = "_stathz" },
148 1.75 enami #define X_NCHSTATS 3
149 1.153 christos { .n_name = "_nchstats" },
150 1.133 chs #define X_KMEMSTAT 4
151 1.153 christos { .n_name = "_kmemstatistics" },
152 1.133 chs #define X_KMEMBUCKETS 5
153 1.153 christos { .n_name = "_kmembuckets" },
154 1.133 chs #define X_ALLEVENTS 6
155 1.153 christos { .n_name = "_allevents" },
156 1.133 chs #define X_POOLHEAD 7
157 1.153 christos { .n_name = "_pool_head" },
158 1.133 chs #define X_UVMEXP 8
159 1.153 christos { .n_name = "_uvmexp" },
160 1.145 kardel #define X_TIME_SECOND 9
161 1.153 christos { .n_name = "_time_second" },
162 1.147 kardel #define X_TIME 10
163 1.153 christos { .n_name = "_time" },
164 1.147 kardel #define X_NL_SIZE 11
165 1.153 christos { .n_name = NULL },
166 1.90 lukem };
167 1.90 lukem
168 1.90 lukem /*
169 1.133 chs * Namelist for pre-evcnt interrupt counters.
170 1.133 chs */
171 1.133 chs struct nlist intrnl[] =
172 1.133 chs {
173 1.133 chs #define X_INTRNAMES 0
174 1.153 christos { .n_name = "_intrnames" },
175 1.133 chs #define X_EINTRNAMES 1
176 1.153 christos { .n_name = "_eintrnames" },
177 1.133 chs #define X_INTRCNT 2
178 1.153 christos { .n_name = "_intrcnt" },
179 1.133 chs #define X_EINTRCNT 3
180 1.153 christos { .n_name = "_eintrcnt" },
181 1.133 chs #define X_INTRNL_SIZE 4
182 1.153 christos { .n_name = NULL },
183 1.133 chs };
184 1.133 chs
185 1.133 chs
186 1.133 chs /*
187 1.90 lukem * Namelist for hash statistics
188 1.90 lukem */
189 1.90 lukem struct nlist hashnl[] =
190 1.90 lukem {
191 1.90 lukem #define X_NFSNODE 0
192 1.153 christos { .n_name = "_nfsnodehash" },
193 1.90 lukem #define X_NFSNODETBL 1
194 1.153 christos { .n_name = "_nfsnodehashtbl" },
195 1.90 lukem #define X_IHASH 2
196 1.153 christos { .n_name = "_ihash" },
197 1.90 lukem #define X_IHASHTBL 3
198 1.153 christos { .n_name = "_ihashtbl" },
199 1.90 lukem #define X_BUFHASH 4
200 1.153 christos { .n_name = "_bufhash" },
201 1.90 lukem #define X_BUFHASHTBL 5
202 1.153 christos { .n_name = "_bufhashtbl" },
203 1.122 junyoung #define X_UIHASH 6
204 1.153 christos { .n_name = "_uihash" },
205 1.122 junyoung #define X_UIHASHTBL 7
206 1.153 christos { .n_name = "_uihashtbl" },
207 1.122 junyoung #define X_IFADDRHASH 8
208 1.153 christos { .n_name = "_in_ifaddrhash" },
209 1.122 junyoung #define X_IFADDRHASHTBL 9
210 1.153 christos { .n_name = "_in_ifaddrhashtbl" },
211 1.122 junyoung #define X_NCHASH 10
212 1.153 christos { .n_name = "_nchash" },
213 1.122 junyoung #define X_NCHASHTBL 11
214 1.153 christos { .n_name = "_nchashtbl" },
215 1.122 junyoung #define X_NCVHASH 12
216 1.153 christos { .n_name = "_ncvhash" },
217 1.122 junyoung #define X_NCVHASHTBL 13
218 1.153 christos { .n_name = "_ncvhashtbl" },
219 1.122 junyoung #define X_HASHNL_SIZE 14 /* must be last */
220 1.153 christos { .n_name = NULL },
221 1.90 lukem };
222 1.87 lukem
223 1.90 lukem /*
224 1.90 lukem * Namelist for UVM histories
225 1.90 lukem */
226 1.90 lukem struct nlist histnl[] =
227 1.90 lukem {
228 1.153 christos { .n_name = "_uvm_histories" },
229 1.90 lukem #define X_UVM_HISTORIES 0
230 1.153 christos { .n_name = NULL },
231 1.1 cgd };
232 1.1 cgd
233 1.87 lukem
234 1.152 christos #define KILO 1024
235 1.90 lukem
236 1.41 mrg struct uvmexp uvmexp, ouvmexp;
237 1.73 simonb int ndrives;
238 1.1 cgd
239 1.1 cgd int winlines = 20;
240 1.1 cgd
241 1.13 cgd kvm_t *kd;
242 1.13 cgd
243 1.87 lukem #define FORKSTAT 1<<0
244 1.87 lukem #define INTRSTAT 1<<1
245 1.87 lukem #define MEMSTAT 1<<2
246 1.87 lukem #define SUMSTAT 1<<3
247 1.87 lukem #define EVCNTSTAT 1<<4
248 1.87 lukem #define VMSTAT 1<<5
249 1.87 lukem #define HISTLIST 1<<6
250 1.87 lukem #define HISTDUMP 1<<7
251 1.87 lukem #define HASHSTAT 1<<8
252 1.88 lukem #define HASHLIST 1<<9
253 1.130 he #define VMTOTAL 1<<10
254 1.154 ad #define POOLCACHESTAT 1<<11
255 1.1 cgd
256 1.151 yamt /*
257 1.151 yamt * Print single word. `ovflow' is number of characters didn't fit
258 1.151 yamt * on the last word. `fmt' is a format string to print this word.
259 1.151 yamt * It must contain asterisk for field width. `width' is a width
260 1.151 yamt * occupied by this word. `fixed' is a number of constant chars in
261 1.151 yamt * `fmt'. `val' is a value to be printed using format string `fmt'.
262 1.151 yamt */
263 1.151 yamt #define PRWORD(ovflw, fmt, width, fixed, val) do { \
264 1.151 yamt (ovflw) += printf((fmt), \
265 1.151 yamt (width) - (fixed) - (ovflw) > 0 ? \
266 1.151 yamt (width) - (fixed) - (ovflw) : 0, \
267 1.151 yamt (val)) - (width); \
268 1.151 yamt if ((ovflw) < 0) \
269 1.151 yamt (ovflw) = 0; \
270 1.151 yamt } while (/* CONSTCOND */0)
271 1.151 yamt
272 1.151 yamt void cpustats(int *);
273 1.87 lukem void deref_kptr(const void *, void *, size_t, const char *);
274 1.151 yamt void drvstats(int *);
275 1.73 simonb void doevcnt(int verbose);
276 1.88 lukem void dohashstat(int, int, const char *);
277 1.73 simonb void dointr(int verbose);
278 1.73 simonb void domem(void);
279 1.126 simonb void dopool(int, int);
280 1.154 ad void dopoolcache(void);
281 1.73 simonb void dosum(void);
282 1.103 mycroft void dovmstat(struct timespec *, int);
283 1.130 he void print_total_hdr(void);
284 1.130 he void dovmtotal(struct timespec *, int);
285 1.133 chs void kread(struct nlist *, int, void *, size_t);
286 1.147 kardel int kreadc(struct nlist *, int, void *, size_t);
287 1.73 simonb void needhdr(int);
288 1.73 simonb long getuptime(void);
289 1.73 simonb void printhdr(void);
290 1.73 simonb long pct(long, long);
291 1.73 simonb void usage(void);
292 1.73 simonb void doforkst(void);
293 1.73 simonb
294 1.73 simonb void hist_traverse(int, const char *);
295 1.73 simonb void hist_dodump(struct uvm_history *);
296 1.73 simonb
297 1.73 simonb int main(int, char **);
298 1.73 simonb char **choosedrives(char **);
299 1.38 mrg
300 1.29 thorpej /* Namelist and memory file names. */
301 1.29 thorpej char *nlistf, *memf;
302 1.29 thorpej
303 1.47 mrg /* allow old usage [vmstat 1] */
304 1.47 mrg #define BACKWARD_COMPATIBILITY
305 1.47 mrg
306 1.38 mrg int
307 1.75 enami main(int argc, char *argv[])
308 1.1 cgd {
309 1.126 simonb int c, todo, verbose, wide;
310 1.103 mycroft struct timespec interval;
311 1.1 cgd int reps;
312 1.75 enami char errbuf[_POSIX2_LINE_MAX];
313 1.75 enami gid_t egid = getegid();
314 1.88 lukem const char *histname, *hashname;
315 1.1 cgd
316 1.88 lukem histname = hashname = NULL;
317 1.48 mrg (void)setegid(getgid());
318 1.13 cgd memf = nlistf = NULL;
319 1.126 simonb reps = todo = verbose = wide = 0;
320 1.103 mycroft interval.tv_sec = 0;
321 1.103 mycroft interval.tv_nsec = 0;
322 1.154 ad while ((c = getopt(argc, argv, "Cc:efh:HilLM:mN:stu:UvWw:")) != -1) {
323 1.1 cgd switch (c) {
324 1.1 cgd case 'c':
325 1.1 cgd reps = atoi(optarg);
326 1.1 cgd break;
327 1.154 ad case 'C':
328 1.154 ad todo |= POOLCACHESTAT;
329 1.154 ad break;
330 1.66 cgd case 'e':
331 1.66 cgd todo |= EVCNTSTAT;
332 1.66 cgd break;
333 1.1 cgd case 'f':
334 1.1 cgd todo |= FORKSTAT;
335 1.1 cgd break;
336 1.45 thorpej case 'h':
337 1.88 lukem hashname = optarg;
338 1.88 lukem /* FALLTHROUGH */
339 1.88 lukem case 'H':
340 1.87 lukem todo |= HASHSTAT;
341 1.45 thorpej break;
342 1.1 cgd case 'i':
343 1.1 cgd todo |= INTRSTAT;
344 1.1 cgd break;
345 1.45 thorpej case 'l':
346 1.45 thorpej todo |= HISTLIST;
347 1.45 thorpej break;
348 1.88 lukem case 'L':
349 1.88 lukem todo |= HASHLIST;
350 1.88 lukem break;
351 1.1 cgd case 'M':
352 1.13 cgd memf = optarg;
353 1.1 cgd break;
354 1.1 cgd case 'm':
355 1.1 cgd todo |= MEMSTAT;
356 1.1 cgd break;
357 1.1 cgd case 'N':
358 1.13 cgd nlistf = optarg;
359 1.1 cgd break;
360 1.1 cgd case 's':
361 1.1 cgd todo |= SUMSTAT;
362 1.1 cgd break;
363 1.130 he case 't':
364 1.130 he todo |= VMTOTAL;
365 1.130 he break;
366 1.87 lukem case 'u':
367 1.87 lukem histname = optarg;
368 1.87 lukem /* FALLTHROUGH */
369 1.87 lukem case 'U':
370 1.87 lukem todo |= HISTDUMP;
371 1.87 lukem break;
372 1.66 cgd case 'v':
373 1.87 lukem verbose++;
374 1.66 cgd break;
375 1.126 simonb case 'W':
376 1.126 simonb wide++;
377 1.126 simonb break;
378 1.1 cgd case 'w':
379 1.103 mycroft interval.tv_sec = atol(optarg);
380 1.1 cgd break;
381 1.1 cgd case '?':
382 1.1 cgd default:
383 1.1 cgd usage();
384 1.1 cgd }
385 1.1 cgd }
386 1.1 cgd argc -= optind;
387 1.1 cgd argv += optind;
388 1.1 cgd
389 1.1 cgd if (todo == 0)
390 1.1 cgd todo = VMSTAT;
391 1.1 cgd
392 1.13 cgd /*
393 1.48 mrg * Discard setgid privileges. If not the running kernel, we toss
394 1.48 mrg * them away totally so that bad guys can't print interesting stuff
395 1.48 mrg * from kernel memory, otherwise switch back to kmem for the
396 1.48 mrg * duration of the kvm_openfiles() call.
397 1.13 cgd */
398 1.13 cgd if (nlistf != NULL || memf != NULL)
399 1.48 mrg (void)setgid(getgid());
400 1.48 mrg else
401 1.48 mrg (void)setegid(egid);
402 1.13 cgd
403 1.75 enami kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
404 1.75 enami if (kd == NULL)
405 1.87 lukem errx(1, "kvm_openfiles: %s", errbuf);
406 1.48 mrg
407 1.95 simonb if (nlistf == NULL && memf == NULL)
408 1.95 simonb (void)setgid(getgid());
409 1.1 cgd
410 1.13 cgd if ((c = kvm_nlist(kd, namelist)) != 0) {
411 1.147 kardel int doexit = 0;
412 1.90 lukem if (c == -1)
413 1.90 lukem errx(1, "kvm_nlist: %s %s", "namelist", kvm_geterr(kd));
414 1.110 matt for (c = 0; c < sizeof(namelist) / sizeof(namelist[0])-1; c++)
415 1.147 kardel if (namelist[c].n_type == 0 &&
416 1.147 kardel c != X_TIME_SECOND &&
417 1.147 kardel c != X_TIME) {
418 1.147 kardel if (doexit++ == 0)
419 1.147 kardel (void)fprintf(stderr, "vmstat: undefined symbols:");
420 1.153 christos (void)fprintf(stderr, " %s",
421 1.153 christos namelist[c].n_name);
422 1.147 kardel }
423 1.147 kardel if (doexit) {
424 1.147 kardel (void)fputc('\n', stderr);
425 1.147 kardel exit(1);
426 1.147 kardel }
427 1.1 cgd }
428 1.133 chs if (todo & INTRSTAT)
429 1.133 chs (void) kvm_nlist(kd, intrnl);
430 1.90 lukem if ((c = kvm_nlist(kd, hashnl)) == -1 || c == X_HASHNL_SIZE)
431 1.90 lukem errx(1, "kvm_nlist: %s %s", "hashnl", kvm_geterr(kd));
432 1.90 lukem if (kvm_nlist(kd, histnl) == -1)
433 1.90 lukem errx(1, "kvm_nlist: %s %s", "histnl", kvm_geterr(kd));
434 1.1 cgd
435 1.1 cgd if (todo & VMSTAT) {
436 1.1 cgd struct winsize winsize;
437 1.1 cgd
438 1.153 christos (void)drvinit(0);/* Initialize disk stats, no disks selected. */
439 1.49 drochner
440 1.49 drochner (void)setgid(getgid()); /* don't need privs anymore */
441 1.49 drochner
442 1.29 thorpej argv = choosedrives(argv); /* Select disks. */
443 1.1 cgd winsize.ws_row = 0;
444 1.115 simonb (void)ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize);
445 1.1 cgd if (winsize.ws_row > 0)
446 1.1 cgd winlines = winsize.ws_row;
447 1.1 cgd
448 1.1 cgd }
449 1.1 cgd
450 1.1 cgd #ifdef BACKWARD_COMPATIBILITY
451 1.1 cgd if (*argv) {
452 1.103 mycroft interval.tv_sec = atol(*argv);
453 1.1 cgd if (*++argv)
454 1.1 cgd reps = atoi(*argv);
455 1.1 cgd }
456 1.1 cgd #endif
457 1.1 cgd
458 1.103 mycroft if (interval.tv_sec) {
459 1.1 cgd if (!reps)
460 1.1 cgd reps = -1;
461 1.1 cgd } else if (reps)
462 1.103 mycroft interval.tv_sec = 1;
463 1.1 cgd
464 1.78 jhawk
465 1.78 jhawk /*
466 1.78 jhawk * Statistics dumping is incompatible with the default
467 1.78 jhawk * VMSTAT/dovmstat() output. So perform the interval/reps handling
468 1.78 jhawk * for it here.
469 1.78 jhawk */
470 1.130 he if ((todo & (VMSTAT|VMTOTAL)) == 0) {
471 1.99 enami for (;;) {
472 1.99 enami if (todo & (HISTLIST|HISTDUMP)) {
473 1.99 enami if ((todo & (HISTLIST|HISTDUMP)) ==
474 1.99 enami (HISTLIST|HISTDUMP))
475 1.99 enami errx(1, "you may list or dump,"
476 1.99 enami " but not both!");
477 1.99 enami hist_traverse(todo, histname);
478 1.153 christos (void)putchar('\n');
479 1.99 enami }
480 1.99 enami if (todo & FORKSTAT) {
481 1.99 enami doforkst();
482 1.153 christos (void)putchar('\n');
483 1.99 enami }
484 1.99 enami if (todo & MEMSTAT) {
485 1.99 enami domem();
486 1.126 simonb dopool(verbose, wide);
487 1.153 christos (void)putchar('\n');
488 1.99 enami }
489 1.154 ad if (todo & POOLCACHESTAT) {
490 1.154 ad dopoolcache();
491 1.154 ad (void)putchar('\n');
492 1.154 ad }
493 1.99 enami if (todo & SUMSTAT) {
494 1.99 enami dosum();
495 1.153 christos (void)putchar('\n');
496 1.99 enami }
497 1.99 enami if (todo & INTRSTAT) {
498 1.99 enami dointr(verbose);
499 1.153 christos (void)putchar('\n');
500 1.99 enami }
501 1.99 enami if (todo & EVCNTSTAT) {
502 1.99 enami doevcnt(verbose);
503 1.153 christos (void)putchar('\n');
504 1.99 enami }
505 1.99 enami if (todo & (HASHLIST|HASHSTAT)) {
506 1.99 enami if ((todo & (HASHLIST|HASHSTAT)) ==
507 1.99 enami (HASHLIST|HASHSTAT))
508 1.99 enami errx(1, "you may list or display,"
509 1.99 enami " but not both!");
510 1.99 enami dohashstat(verbose, todo, hashname);
511 1.153 christos (void)putchar('\n');
512 1.99 enami }
513 1.101 sommerfe
514 1.101 sommerfe if (reps >= 0 && --reps <=0)
515 1.99 enami break;
516 1.153 christos (void)nanosleep(&interval, NULL);
517 1.87 lukem }
518 1.130 he } else {
519 1.130 he if ((todo & (VMSTAT|VMTOTAL)) == (VMSTAT|VMTOTAL)) {
520 1.130 he errx(1, "you may not both do vmstat and vmtotal");
521 1.130 he }
522 1.130 he if (todo & VMSTAT)
523 1.130 he dovmstat(&interval, reps);
524 1.130 he if (todo & VMTOTAL)
525 1.130 he dovmtotal(&interval, reps);
526 1.130 he }
527 1.153 christos return 0;
528 1.1 cgd }
529 1.1 cgd
530 1.1 cgd char **
531 1.73 simonb choosedrives(char **argv)
532 1.1 cgd {
533 1.38 mrg int i;
534 1.1 cgd
535 1.1 cgd /*
536 1.1 cgd * Choose drives to be displayed. Priority goes to (in order) drives
537 1.1 cgd * supplied as arguments, default drives. If everything isn't filled
538 1.1 cgd * in and there are drives not taken care of, display the first few
539 1.1 cgd * that fit.
540 1.1 cgd */
541 1.75 enami #define BACKWARD_COMPATIBILITY
542 1.1 cgd for (ndrives = 0; *argv; ++argv) {
543 1.1 cgd #ifdef BACKWARD_COMPATIBILITY
544 1.124 dsl if (isdigit((unsigned char)**argv))
545 1.1 cgd break;
546 1.1 cgd #endif
547 1.140 blymn for (i = 0; i < ndrive; i++) {
548 1.1 cgd if (strcmp(dr_name[i], *argv))
549 1.1 cgd continue;
550 1.140 blymn drv_select[i] = 1;
551 1.136 blymn ++ndrives;
552 1.136 blymn break;
553 1.136 blymn }
554 1.1 cgd }
555 1.151 yamt for (i = 0; i < ndrive && ndrives < 2; i++) {
556 1.140 blymn if (drv_select[i])
557 1.1 cgd continue;
558 1.140 blymn drv_select[i] = 1;
559 1.1 cgd ++ndrives;
560 1.1 cgd }
561 1.140 blymn
562 1.75 enami return (argv);
563 1.1 cgd }
564 1.1 cgd
565 1.1 cgd long
566 1.73 simonb getuptime(void)
567 1.1 cgd {
568 1.30 cgd static struct timeval boottime;
569 1.145 kardel struct timeval now;
570 1.149 kardel time_t uptime, nowsec;
571 1.1 cgd
572 1.30 cgd if (boottime.tv_sec == 0)
573 1.133 chs kread(namelist, X_BOOTTIME, &boottime, sizeof(boottime));
574 1.149 kardel if (kreadc(namelist, X_TIME_SECOND, &nowsec, sizeof(nowsec))) {
575 1.149 kardel /*
576 1.149 kardel * XXX this assignment dance can be removed once timeval tv_sec
577 1.149 kardel * is SUS mandated time_t
578 1.149 kardel */
579 1.149 kardel now.tv_sec = nowsec;
580 1.147 kardel now.tv_usec = 0;
581 1.147 kardel } else {
582 1.147 kardel kread(namelist, X_TIME, &now, sizeof(now));
583 1.147 kardel }
584 1.145 kardel uptime = now.tv_sec - boottime.tv_sec;
585 1.87 lukem if (uptime <= 0 || uptime > 60*60*24*365*10)
586 1.87 lukem errx(1, "time makes no sense; namelist must be wrong.");
587 1.75 enami return (uptime);
588 1.1 cgd }
589 1.1 cgd
590 1.1 cgd int hz, hdrcnt;
591 1.1 cgd
592 1.1 cgd void
593 1.130 he print_total_hdr()
594 1.130 he {
595 1.130 he
596 1.130 he (void)printf("procs memory\n");
597 1.130 he (void)printf("ru dw pw sl sw");
598 1.130 he (void)printf(" total-v active-v active-r");
599 1.130 he (void)printf(" vm-sh avm-sh rm-sh arm-sh free\n");
600 1.130 he hdrcnt = winlines - 2;
601 1.130 he }
602 1.130 he
603 1.130 he void
604 1.130 he dovmtotal(struct timespec *interval, int reps)
605 1.130 he {
606 1.130 he struct vmtotal total;
607 1.130 he int mib[2];
608 1.130 he size_t size;
609 1.130 he
610 1.130 he (void)signal(SIGCONT, needhdr);
611 1.130 he
612 1.130 he for (hdrcnt = 1;;) {
613 1.130 he if (!--hdrcnt)
614 1.130 he print_total_hdr();
615 1.130 he if (memf != NULL) {
616 1.153 christos (void)printf(
617 1.153 christos "Unable to get vmtotals from crash dump.\n");
618 1.153 christos (void)memset(&total, 0, sizeof(total));
619 1.130 he } else {
620 1.130 he size = sizeof(total);
621 1.130 he mib[0] = CTL_VM;
622 1.130 he mib[1] = VM_METER;
623 1.130 he if (sysctl(mib, 2, &total, &size, NULL, 0) < 0) {
624 1.153 christos (void)printf("Can't get vmtotals: %s\n",
625 1.130 he strerror(errno));
626 1.153 christos (void)memset(&total, 0, sizeof(total));
627 1.130 he }
628 1.130 he }
629 1.153 christos (void)printf("%2d ", total.t_rq);
630 1.153 christos (void)printf("%2d ", total.t_dw);
631 1.153 christos (void)printf("%2d ", total.t_pw);
632 1.153 christos (void)printf("%2d ", total.t_sl);
633 1.153 christos (void)printf("%2d ", total.t_sw);
634 1.153 christos
635 1.153 christos (void)printf("%9d ", total.t_vm);
636 1.153 christos (void)printf("%9d ", total.t_avm);
637 1.153 christos (void)printf("%9d ", total.t_arm);
638 1.153 christos (void)printf("%5d ", total.t_vmshr);
639 1.153 christos (void)printf("%6d ", total.t_avmshr);
640 1.153 christos (void)printf("%5d ", total.t_rmshr);
641 1.153 christos (void)printf("%6d ", total.t_armshr);
642 1.153 christos (void)printf("%5d", total.t_free);
643 1.130 he
644 1.153 christos (void)putchar('\n');
645 1.130 he
646 1.130 he (void)fflush(stdout);
647 1.130 he if (reps >= 0 && --reps <= 0)
648 1.130 he break;
649 1.130 he
650 1.153 christos (void)nanosleep(interval, NULL);
651 1.130 he }
652 1.130 he }
653 1.130 he
654 1.130 he void
655 1.103 mycroft dovmstat(struct timespec *interval, int reps)
656 1.1 cgd {
657 1.1 cgd struct vmtotal total;
658 1.1 cgd time_t uptime, halfuptime;
659 1.17 cgd int mib[2];
660 1.17 cgd size_t size;
661 1.41 mrg int pagesize = getpagesize();
662 1.151 yamt int ovflw;
663 1.1 cgd
664 1.1 cgd uptime = getuptime();
665 1.1 cgd halfuptime = uptime / 2;
666 1.1 cgd (void)signal(SIGCONT, needhdr);
667 1.1 cgd
668 1.13 cgd if (namelist[X_STATHZ].n_type != 0 && namelist[X_STATHZ].n_value != 0)
669 1.133 chs kread(namelist, X_STATHZ, &hz, sizeof(hz));
670 1.1 cgd if (!hz)
671 1.133 chs kread(namelist, X_HZ, &hz, sizeof(hz));
672 1.1 cgd
673 1.1 cgd for (hdrcnt = 1;;) {
674 1.1 cgd if (!--hdrcnt)
675 1.1 cgd printhdr();
676 1.29 thorpej /* Read new disk statistics */
677 1.139 dsl cpureadstats();
678 1.140 blymn drvreadstats();
679 1.139 dsl tkreadstats();
680 1.133 chs kread(namelist, X_UVMEXP, &uvmexp, sizeof(uvmexp));
681 1.58 thorpej if (memf != NULL) {
682 1.58 thorpej /*
683 1.58 thorpej * XXX Can't do this if we're reading a crash
684 1.58 thorpej * XXX dump because they're lazily-calculated.
685 1.58 thorpej */
686 1.153 christos (void)printf(
687 1.153 christos "Unable to get vmtotals from crash dump.\n");
688 1.153 christos (void)memset(&total, 0, sizeof(total));
689 1.58 thorpej } else {
690 1.58 thorpej size = sizeof(total);
691 1.58 thorpej mib[0] = CTL_VM;
692 1.58 thorpej mib[1] = VM_METER;
693 1.58 thorpej if (sysctl(mib, 2, &total, &size, NULL, 0) < 0) {
694 1.153 christos (void)printf("Can't get vmtotals: %s\n",
695 1.58 thorpej strerror(errno));
696 1.153 christos (void)memset(&total, 0, sizeof(total));
697 1.58 thorpej }
698 1.13 cgd }
699 1.151 yamt ovflw = 0;
700 1.151 yamt PRWORD(ovflw, " %*d", 2, 1, total.t_rq - 1);
701 1.151 yamt PRWORD(ovflw, " %*d", 2, 1, total.t_dw + total.t_pw);
702 1.151 yamt PRWORD(ovflw, " %*d", 2, 1, total.t_sw);
703 1.153 christos #define pgtok(a) (long)((a) * ((uint32_t)pagesize >> 10))
704 1.38 mrg #define rate(x) (u_long)(((x) + halfuptime) / uptime) /* round */
705 1.151 yamt PRWORD(ovflw, " %*ld", 7, 1, pgtok(total.t_avm));
706 1.151 yamt PRWORD(ovflw, " %*ld", 7, 1, pgtok(total.t_free));
707 1.151 yamt PRWORD(ovflw, " %*ld", 5, 1,
708 1.151 yamt rate(uvmexp.faults - ouvmexp.faults));
709 1.151 yamt PRWORD(ovflw, " %*ld", 4, 1,
710 1.151 yamt rate(uvmexp.pdreact - ouvmexp.pdreact));
711 1.151 yamt PRWORD(ovflw, " %*ld", 4, 1,
712 1.151 yamt rate(uvmexp.pageins - ouvmexp.pageins));
713 1.151 yamt PRWORD(ovflw, " %*ld", 5, 1,
714 1.44 mrg rate(uvmexp.pgswapout - ouvmexp.pgswapout));
715 1.151 yamt PRWORD(ovflw, " %*ld", 5, 1,
716 1.151 yamt rate(uvmexp.pdfreed - ouvmexp.pdfreed));
717 1.151 yamt PRWORD(ovflw, " %*ld", 6, 2,
718 1.151 yamt rate(uvmexp.pdscans - ouvmexp.pdscans));
719 1.151 yamt drvstats(&ovflw);
720 1.151 yamt PRWORD(ovflw, " %*ld", 5, 1,
721 1.151 yamt rate(uvmexp.intrs - ouvmexp.intrs));
722 1.151 yamt PRWORD(ovflw, " %*ld", 5, 1,
723 1.151 yamt rate(uvmexp.syscalls - ouvmexp.syscalls));
724 1.151 yamt PRWORD(ovflw, " %*ld", 4, 1,
725 1.42 mrg rate(uvmexp.swtch - ouvmexp.swtch));
726 1.151 yamt cpustats(&ovflw);
727 1.153 christos (void)putchar('\n');
728 1.42 mrg (void)fflush(stdout);
729 1.42 mrg if (reps >= 0 && --reps <= 0)
730 1.42 mrg break;
731 1.42 mrg ouvmexp = uvmexp;
732 1.103 mycroft uptime = interval->tv_sec;
733 1.1 cgd /*
734 1.1 cgd * We round upward to avoid losing low-frequency events
735 1.1 cgd * (i.e., >= 1 per interval but < 1 per second).
736 1.1 cgd */
737 1.33 thorpej halfuptime = uptime == 1 ? 0 : (uptime + 1) / 2;
738 1.153 christos (void)nanosleep(interval, NULL);
739 1.1 cgd }
740 1.1 cgd }
741 1.1 cgd
742 1.38 mrg void
743 1.73 simonb printhdr(void)
744 1.1 cgd {
745 1.38 mrg int i;
746 1.1 cgd
747 1.104 mrg (void)printf(" procs memory page%*s", 23, "");
748 1.29 thorpej if (ndrives > 0)
749 1.70 sommerfe (void)printf("%s %*sfaults cpu\n",
750 1.75 enami ((ndrives > 1) ? "disks" : "disk"),
751 1.75 enami ((ndrives > 1) ? ndrives * 3 - 4 : 0), "");
752 1.1 cgd else
753 1.29 thorpej (void)printf("%*s faults cpu\n",
754 1.75 enami ndrives * 3, "");
755 1.29 thorpej
756 1.104 mrg (void)printf(" r b w avm fre flt re pi po fr sr ");
757 1.140 blymn for (i = 0; i < ndrive; i++)
758 1.140 blymn if (drv_select[i])
759 1.1 cgd (void)printf("%c%c ", dr_name[i][0],
760 1.1 cgd dr_name[i][strlen(dr_name[i]) - 1]);
761 1.1 cgd (void)printf(" in sy cs us sy id\n");
762 1.1 cgd hdrcnt = winlines - 2;
763 1.1 cgd }
764 1.1 cgd
765 1.1 cgd /*
766 1.1 cgd * Force a header to be prepended to the next output.
767 1.1 cgd */
768 1.1 cgd void
769 1.153 christos /*ARGSUSED*/
770 1.73 simonb needhdr(int dummy)
771 1.1 cgd {
772 1.1 cgd
773 1.1 cgd hdrcnt = 1;
774 1.1 cgd }
775 1.1 cgd
776 1.38 mrg long
777 1.73 simonb pct(long top, long bot)
778 1.1 cgd {
779 1.13 cgd long ans;
780 1.13 cgd
781 1.1 cgd if (bot == 0)
782 1.75 enami return (0);
783 1.153 christos ans = (long)((quad_t)top * 100 / bot);
784 1.13 cgd return (ans);
785 1.1 cgd }
786 1.1 cgd
787 1.38 mrg #define PCT(top, bot) (int)pct((long)(top), (long)(bot))
788 1.1 cgd
789 1.1 cgd void
790 1.73 simonb dosum(void)
791 1.1 cgd {
792 1.1 cgd struct nchstats nchstats;
793 1.123 enami u_long nchtotal;
794 1.1 cgd
795 1.133 chs kread(namelist, X_UVMEXP, &uvmexp, sizeof(uvmexp));
796 1.41 mrg
797 1.44 mrg (void)printf("%9u bytes per page\n", uvmexp.pagesize);
798 1.44 mrg
799 1.81 thorpej (void)printf("%9u page color%s\n",
800 1.81 thorpej uvmexp.ncolors, uvmexp.ncolors == 1 ? "" : "s");
801 1.81 thorpej
802 1.44 mrg (void)printf("%9u pages managed\n", uvmexp.npages);
803 1.44 mrg (void)printf("%9u pages free\n", uvmexp.free);
804 1.44 mrg (void)printf("%9u pages paging\n", uvmexp.paging);
805 1.44 mrg (void)printf("%9u pages wired\n", uvmexp.wired);
806 1.63 thorpej (void)printf("%9u zero pages\n", uvmexp.zeropages);
807 1.44 mrg (void)printf("%9u reserve pagedaemon pages\n",
808 1.44 mrg uvmexp.reserve_pagedaemon);
809 1.44 mrg (void)printf("%9u reserve kernel pages\n", uvmexp.reserve_kernel);
810 1.94 chs (void)printf("%9u anonymous pages\n", uvmexp.anonpages);
811 1.94 chs (void)printf("%9u cached file pages\n", uvmexp.filepages);
812 1.94 chs (void)printf("%9u cached executable pages\n", uvmexp.execpages);
813 1.44 mrg
814 1.44 mrg (void)printf("%9u minimum free pages\n", uvmexp.freemin);
815 1.44 mrg (void)printf("%9u target free pages\n", uvmexp.freetarg);
816 1.44 mrg (void)printf("%9u maximum wired pages\n", uvmexp.wiredmax);
817 1.44 mrg
818 1.44 mrg (void)printf("%9u swap devices\n", uvmexp.nswapdev);
819 1.44 mrg (void)printf("%9u swap pages\n", uvmexp.swpages);
820 1.44 mrg (void)printf("%9u swap pages in use\n", uvmexp.swpginuse);
821 1.44 mrg (void)printf("%9u swap allocations\n", uvmexp.nswget);
822 1.44 mrg
823 1.43 mrg (void)printf("%9u total faults taken\n", uvmexp.faults);
824 1.43 mrg (void)printf("%9u traps\n", uvmexp.traps);
825 1.43 mrg (void)printf("%9u device interrupts\n", uvmexp.intrs);
826 1.121 wiz (void)printf("%9u CPU context switches\n", uvmexp.swtch);
827 1.43 mrg (void)printf("%9u software interrupts\n", uvmexp.softs);
828 1.43 mrg (void)printf("%9u system calls\n", uvmexp.syscalls);
829 1.60 fredb (void)printf("%9u pagein requests\n", uvmexp.pageins);
830 1.60 fredb (void)printf("%9u pageout requests\n", uvmexp.pdpageouts);
831 1.43 mrg (void)printf("%9u swap ins\n", uvmexp.swapins);
832 1.43 mrg (void)printf("%9u swap outs\n", uvmexp.swapouts);
833 1.60 fredb (void)printf("%9u pages swapped in\n", uvmexp.pgswapin);
834 1.60 fredb (void)printf("%9u pages swapped out\n", uvmexp.pgswapout);
835 1.43 mrg (void)printf("%9u forks total\n", uvmexp.forks);
836 1.43 mrg (void)printf("%9u forks blocked parent\n", uvmexp.forks_ppwait);
837 1.43 mrg (void)printf("%9u forks shared address space with parent\n",
838 1.43 mrg uvmexp.forks_sharevm);
839 1.63 thorpej (void)printf("%9u pagealloc zero wanted and avail\n",
840 1.63 thorpej uvmexp.pga_zerohit);
841 1.63 thorpej (void)printf("%9u pagealloc zero wanted and not avail\n",
842 1.63 thorpej uvmexp.pga_zeromiss);
843 1.68 thorpej (void)printf("%9u aborts of idle page zeroing\n",
844 1.68 thorpej uvmexp.zeroaborts);
845 1.79 thorpej (void)printf("%9u pagealloc desired color avail\n",
846 1.79 thorpej uvmexp.colorhit);
847 1.79 thorpej (void)printf("%9u pagealloc desired color not avail\n",
848 1.79 thorpej uvmexp.colormiss);
849 1.44 mrg
850 1.44 mrg (void)printf("%9u faults with no memory\n", uvmexp.fltnoram);
851 1.44 mrg (void)printf("%9u faults with no anons\n", uvmexp.fltnoanon);
852 1.43 mrg (void)printf("%9u faults had to wait on pages\n", uvmexp.fltpgwait);
853 1.43 mrg (void)printf("%9u faults found released page\n", uvmexp.fltpgrele);
854 1.43 mrg (void)printf("%9u faults relock (%u ok)\n", uvmexp.fltrelck,
855 1.43 mrg uvmexp.fltrelckok);
856 1.43 mrg (void)printf("%9u anon page faults\n", uvmexp.fltanget);
857 1.43 mrg (void)printf("%9u anon retry faults\n", uvmexp.fltanretry);
858 1.43 mrg (void)printf("%9u amap copy faults\n", uvmexp.fltamcopy);
859 1.43 mrg (void)printf("%9u neighbour anon page faults\n", uvmexp.fltnamap);
860 1.43 mrg (void)printf("%9u neighbour object page faults\n", uvmexp.fltnomap);
861 1.43 mrg (void)printf("%9u locked pager get faults\n", uvmexp.fltlget);
862 1.43 mrg (void)printf("%9u unlocked pager get faults\n", uvmexp.fltget);
863 1.43 mrg (void)printf("%9u anon faults\n", uvmexp.flt_anon);
864 1.43 mrg (void)printf("%9u anon copy on write faults\n", uvmexp.flt_acow);
865 1.43 mrg (void)printf("%9u object faults\n", uvmexp.flt_obj);
866 1.43 mrg (void)printf("%9u promote copy faults\n", uvmexp.flt_prcopy);
867 1.43 mrg (void)printf("%9u promote zero fill faults\n", uvmexp.flt_przero);
868 1.44 mrg
869 1.44 mrg (void)printf("%9u times daemon wokeup\n",uvmexp.pdwoke);
870 1.44 mrg (void)printf("%9u revolutions of the clock hand\n", uvmexp.pdrevs);
871 1.44 mrg (void)printf("%9u times daemon attempted swapout\n", uvmexp.pdswout);
872 1.44 mrg (void)printf("%9u pages freed by daemon\n", uvmexp.pdfreed);
873 1.44 mrg (void)printf("%9u pages scanned by daemon\n", uvmexp.pdscans);
874 1.75 enami (void)printf("%9u anonymous pages scanned by daemon\n",
875 1.75 enami uvmexp.pdanscan);
876 1.44 mrg (void)printf("%9u object pages scanned by daemon\n", uvmexp.pdobscan);
877 1.44 mrg (void)printf("%9u pages reactivated\n", uvmexp.pdreact);
878 1.44 mrg (void)printf("%9u pages found busy by daemon\n", uvmexp.pdbusy);
879 1.44 mrg (void)printf("%9u total pending pageouts\n", uvmexp.pdpending);
880 1.44 mrg (void)printf("%9u pages deactivated\n", uvmexp.pddeact);
881 1.123 enami
882 1.133 chs kread(namelist, X_NCHSTATS, &nchstats, sizeof(nchstats));
883 1.1 cgd nchtotal = nchstats.ncs_goodhits + nchstats.ncs_neghits +
884 1.1 cgd nchstats.ncs_badhits + nchstats.ncs_falsehits +
885 1.1 cgd nchstats.ncs_miss + nchstats.ncs_long;
886 1.123 enami (void)printf("%9lu total name lookups\n", nchtotal);
887 1.123 enami (void)printf("%9lu good hits\n", nchstats.ncs_goodhits);
888 1.123 enami (void)printf("%9lu negative hits\n", nchstats.ncs_neghits);
889 1.123 enami (void)printf("%9lu bad hits\n", nchstats.ncs_badhits);
890 1.123 enami (void)printf("%9lu false hits\n", nchstats.ncs_falsehits);
891 1.123 enami (void)printf("%9lu miss\n", nchstats.ncs_miss);
892 1.123 enami (void)printf("%9lu too long\n", nchstats.ncs_long);
893 1.123 enami (void)printf("%9lu pass2 hits\n", nchstats.ncs_pass2);
894 1.123 enami (void)printf("%9lu 2passes\n", nchstats.ncs_2passes);
895 1.1 cgd (void)printf(
896 1.1 cgd "%9s cache hits (%d%% pos + %d%% neg) system %d%% per-process\n",
897 1.1 cgd "", PCT(nchstats.ncs_goodhits, nchtotal),
898 1.1 cgd PCT(nchstats.ncs_neghits, nchtotal),
899 1.1 cgd PCT(nchstats.ncs_pass2, nchtotal));
900 1.1 cgd (void)printf("%9s deletions %d%%, falsehits %d%%, toolong %d%%\n", "",
901 1.1 cgd PCT(nchstats.ncs_badhits, nchtotal),
902 1.1 cgd PCT(nchstats.ncs_falsehits, nchtotal),
903 1.1 cgd PCT(nchstats.ncs_long, nchtotal));
904 1.1 cgd }
905 1.1 cgd
906 1.1 cgd void
907 1.73 simonb doforkst(void)
908 1.1 cgd {
909 1.41 mrg
910 1.133 chs kread(namelist, X_UVMEXP, &uvmexp, sizeof(uvmexp));
911 1.58 thorpej
912 1.41 mrg (void)printf("%u forks total\n", uvmexp.forks);
913 1.41 mrg (void)printf("%u forks blocked parent\n", uvmexp.forks_ppwait);
914 1.41 mrg (void)printf("%u forks shared address space with parent\n",
915 1.41 mrg uvmexp.forks_sharevm);
916 1.1 cgd }
917 1.1 cgd
918 1.1 cgd void
919 1.151 yamt drvstats(int *ovflwp)
920 1.1 cgd {
921 1.101 sommerfe int dn;
922 1.1 cgd double etime;
923 1.151 yamt int ovflw = *ovflwp;
924 1.1 cgd
925 1.29 thorpej /* Calculate disk stat deltas. */
926 1.139 dsl cpuswap();
927 1.140 blymn drvswap();
928 1.139 dsl tkswap();
929 1.101 sommerfe etime = cur.cp_etime;
930 1.101 sommerfe
931 1.140 blymn for (dn = 0; dn < ndrive; ++dn) {
932 1.140 blymn if (!drv_select[dn])
933 1.151 yamt continue;
934 1.151 yamt PRWORD(ovflw, " %*.0f", 3, 1,
935 1.151 yamt (cur.rxfer[dn] + cur.wxfer[dn]) / etime);
936 1.136 blymn }
937 1.151 yamt *ovflwp = ovflw;
938 1.136 blymn }
939 1.136 blymn
940 1.136 blymn void
941 1.151 yamt cpustats(int *ovflwp)
942 1.1 cgd {
943 1.38 mrg int state;
944 1.129 dsl double pcnt, total;
945 1.120 dbj double stat_us, stat_sy, stat_id;
946 1.151 yamt int ovflw = *ovflwp;
947 1.1 cgd
948 1.1 cgd total = 0;
949 1.1 cgd for (state = 0; state < CPUSTATES; ++state)
950 1.29 thorpej total += cur.cp_time[state];
951 1.1 cgd if (total)
952 1.129 dsl pcnt = 100 / total;
953 1.1 cgd else
954 1.129 dsl pcnt = 0;
955 1.129 dsl stat_us = (cur.cp_time[CP_USER] + cur.cp_time[CP_NICE]) * pcnt;
956 1.129 dsl stat_sy = (cur.cp_time[CP_SYS] + cur.cp_time[CP_INTR]) * pcnt;
957 1.129 dsl stat_id = cur.cp_time[CP_IDLE] * pcnt;
958 1.151 yamt PRWORD(ovflw, " %*.0f", ((stat_sy >= 100) ? 2 : 3), 1, stat_us);
959 1.151 yamt PRWORD(ovflw, " %*.0f", ((stat_us >= 100 || stat_id >= 100) ? 2 : 3), 1,
960 1.151 yamt stat_sy);
961 1.151 yamt PRWORD(ovflw, " %*.0f", 3, 1, stat_id);
962 1.151 yamt *ovflwp = ovflw;
963 1.1 cgd }
964 1.1 cgd
965 1.1 cgd void
966 1.66 cgd dointr(int verbose)
967 1.1 cgd {
968 1.138 nonaka unsigned long *intrcnt, *ointrcnt;
969 1.85 enami unsigned long long inttotal, uptime;
970 1.38 mrg int nintr, inamlen;
971 1.138 nonaka char *intrname, *ointrname;
972 1.28 cgd struct evcntlist allevents;
973 1.28 cgd struct evcnt evcnt, *evptr;
974 1.66 cgd char evgroup[EVCNT_STRING_MAX], evname[EVCNT_STRING_MAX];
975 1.1 cgd
976 1.133 chs inttotal = 0;
977 1.1 cgd uptime = getuptime();
978 1.83 matt (void)printf("%-34s %16s %8s\n", "interrupt", "total", "rate");
979 1.133 chs nintr = intrnl[X_EINTRCNT].n_value - intrnl[X_INTRCNT].n_value;
980 1.133 chs inamlen = intrnl[X_EINTRNAMES].n_value - intrnl[X_INTRNAMES].n_value;
981 1.133 chs if (nintr != 0 && inamlen != 0) {
982 1.138 nonaka ointrcnt = intrcnt = malloc((size_t)nintr);
983 1.138 nonaka ointrname = intrname = malloc((size_t)inamlen);
984 1.133 chs if (intrcnt == NULL || intrname == NULL)
985 1.133 chs errx(1, "%s", "");
986 1.133 chs kread(intrnl, X_INTRCNT, intrcnt, (size_t)nintr);
987 1.133 chs kread(intrnl, X_INTRNAMES, intrname, (size_t)inamlen);
988 1.133 chs nintr /= sizeof(long);
989 1.133 chs while (--nintr >= 0) {
990 1.133 chs if (*intrcnt || verbose)
991 1.133 chs (void)printf("%-34s %16llu %8llu\n", intrname,
992 1.133 chs (unsigned long long)*intrcnt,
993 1.133 chs (unsigned long long)
994 1.133 chs (*intrcnt / uptime));
995 1.133 chs intrname += strlen(intrname) + 1;
996 1.133 chs inttotal += *intrcnt++;
997 1.133 chs }
998 1.138 nonaka free(ointrcnt);
999 1.138 nonaka free(ointrname);
1000 1.1 cgd }
1001 1.133 chs
1002 1.133 chs kread(namelist, X_ALLEVENTS, &allevents, sizeof allevents);
1003 1.133 chs evptr = TAILQ_FIRST(&allevents);
1004 1.28 cgd while (evptr) {
1005 1.87 lukem deref_kptr(evptr, &evcnt, sizeof(evcnt), "event chain trashed");
1006 1.133 chs evptr = TAILQ_NEXT(&evcnt, ev_list);
1007 1.66 cgd if (evcnt.ev_type != EVCNT_TYPE_INTR)
1008 1.66 cgd continue;
1009 1.66 cgd
1010 1.66 cgd if (evcnt.ev_count == 0 && !verbose)
1011 1.66 cgd continue;
1012 1.66 cgd
1013 1.153 christos deref_kptr(evcnt.ev_group, evgroup,
1014 1.153 christos (size_t)evcnt.ev_grouplen + 1, "event chain trashed");
1015 1.153 christos deref_kptr(evcnt.ev_name, evname,
1016 1.153 christos (size_t)evcnt.ev_namelen + 1, "event chain trashed");
1017 1.66 cgd
1018 1.85 enami (void)printf("%s %s%*s %16llu %8llu\n", evgroup, evname,
1019 1.83 matt 34 - (evcnt.ev_grouplen + 1 + evcnt.ev_namelen), "",
1020 1.85 enami (unsigned long long)evcnt.ev_count,
1021 1.85 enami (unsigned long long)(evcnt.ev_count / uptime));
1022 1.66 cgd
1023 1.66 cgd inttotal += evcnt.ev_count++;
1024 1.66 cgd }
1025 1.85 enami (void)printf("%-34s %16llu %8llu\n", "Total", inttotal,
1026 1.85 enami (unsigned long long)(inttotal / uptime));
1027 1.66 cgd }
1028 1.66 cgd
1029 1.66 cgd void
1030 1.66 cgd doevcnt(int verbose)
1031 1.66 cgd {
1032 1.83 matt static const char * evtypes [] = { "misc", "intr", "trap" };
1033 1.85 enami unsigned long long uptime;
1034 1.66 cgd struct evcntlist allevents;
1035 1.66 cgd struct evcnt evcnt, *evptr;
1036 1.66 cgd char evgroup[EVCNT_STRING_MAX], evname[EVCNT_STRING_MAX];
1037 1.66 cgd
1038 1.66 cgd /* XXX should print type! */
1039 1.66 cgd
1040 1.66 cgd uptime = getuptime();
1041 1.83 matt (void)printf("%-34s %16s %8s %s\n", "event", "total", "rate", "type");
1042 1.133 chs kread(namelist, X_ALLEVENTS, &allevents, sizeof allevents);
1043 1.133 chs evptr = TAILQ_FIRST(&allevents);
1044 1.66 cgd while (evptr) {
1045 1.87 lukem deref_kptr(evptr, &evcnt, sizeof(evcnt), "event chain trashed");
1046 1.32 cgd
1047 1.133 chs evptr = TAILQ_NEXT(&evcnt, ev_list);
1048 1.66 cgd if (evcnt.ev_count == 0 && !verbose)
1049 1.66 cgd continue;
1050 1.66 cgd
1051 1.153 christos deref_kptr(evcnt.ev_group, evgroup,
1052 1.153 christos (size_t)evcnt.ev_grouplen + 1, "event chain trashed");
1053 1.153 christos deref_kptr(evcnt.ev_name, evname,
1054 1.153 christos (size_t)evcnt.ev_namelen + 1, "event chain trashed");
1055 1.66 cgd
1056 1.85 enami (void)printf("%s %s%*s %16llu %8llu %s\n", evgroup, evname,
1057 1.83 matt 34 - (evcnt.ev_grouplen + 1 + evcnt.ev_namelen), "",
1058 1.85 enami (unsigned long long)evcnt.ev_count,
1059 1.85 enami (unsigned long long)(evcnt.ev_count / uptime),
1060 1.86 enami (evcnt.ev_type < sizeof(evtypes)/sizeof(evtypes[0]) ?
1061 1.86 enami evtypes[evcnt.ev_type] : "?"));
1062 1.18 pk }
1063 1.1 cgd }
1064 1.1 cgd
1065 1.109 thorpej static char memname[64];
1066 1.1 cgd
1067 1.1 cgd void
1068 1.73 simonb domem(void)
1069 1.1 cgd {
1070 1.38 mrg struct kmembuckets *kp;
1071 1.109 thorpej struct malloc_type ks, *ksp;
1072 1.38 mrg int i, j;
1073 1.13 cgd int len, size, first;
1074 1.13 cgd long totuse = 0, totfree = 0, totreq = 0;
1075 1.1 cgd struct kmembuckets buckets[MINBUCKET + 16];
1076 1.1 cgd
1077 1.133 chs kread(namelist, X_KMEMBUCKETS, buckets, sizeof(buckets));
1078 1.34 thorpej for (first = 1, i = MINBUCKET, kp = &buckets[i]; i < MINBUCKET + 16;
1079 1.34 thorpej i++, kp++) {
1080 1.1 cgd if (kp->kb_calls == 0)
1081 1.1 cgd continue;
1082 1.34 thorpej if (first) {
1083 1.34 thorpej (void)printf("Memory statistics by bucket size\n");
1084 1.34 thorpej (void)printf(
1085 1.34 thorpej " Size In Use Free Requests HighWater Couldfree\n");
1086 1.34 thorpej first = 0;
1087 1.34 thorpej }
1088 1.1 cgd size = 1 << i;
1089 1.75 enami (void)printf("%8d %8ld %6ld %10ld %7ld %10ld\n", size,
1090 1.75 enami kp->kb_total - kp->kb_totalfree,
1091 1.75 enami kp->kb_totalfree, kp->kb_calls,
1092 1.75 enami kp->kb_highwat, kp->kb_couldfree);
1093 1.1 cgd totfree += size * kp->kb_totalfree;
1094 1.34 thorpej }
1095 1.34 thorpej
1096 1.34 thorpej /*
1097 1.34 thorpej * If kmem statistics are not being gathered by the kernel,
1098 1.34 thorpej * first will still be 1.
1099 1.34 thorpej */
1100 1.34 thorpej if (first) {
1101 1.87 lukem warnx("Kmem statistics are not being gathered by the kernel.");
1102 1.34 thorpej return;
1103 1.1 cgd }
1104 1.1 cgd
1105 1.13 cgd (void)printf("\nMemory usage type by bucket size\n");
1106 1.13 cgd (void)printf(" Size Type(s)\n");
1107 1.13 cgd kp = &buckets[MINBUCKET];
1108 1.13 cgd for (j = 1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1, kp++) {
1109 1.13 cgd if (kp->kb_calls == 0)
1110 1.13 cgd continue;
1111 1.13 cgd first = 1;
1112 1.13 cgd len = 8;
1113 1.133 chs for (kread(namelist, X_KMEMSTAT, &ksp, sizeof(ksp));
1114 1.109 thorpej ksp != NULL; ksp = ks.ks_next) {
1115 1.109 thorpej deref_kptr(ksp, &ks, sizeof(ks), "malloc type");
1116 1.109 thorpej if (ks.ks_calls == 0)
1117 1.13 cgd continue;
1118 1.109 thorpej if ((ks.ks_size & j) == 0)
1119 1.13 cgd continue;
1120 1.109 thorpej deref_kptr(ks.ks_shortdesc, memname,
1121 1.109 thorpej sizeof(memname), "malloc type name");
1122 1.109 thorpej len += 2 + strlen(memname);
1123 1.13 cgd if (first)
1124 1.153 christos (void)printf("%8d %s", j, memname);
1125 1.13 cgd else
1126 1.153 christos (void)printf(",");
1127 1.13 cgd if (len >= 80) {
1128 1.153 christos (void)printf("\n\t ");
1129 1.109 thorpej len = 10 + strlen(memname);
1130 1.13 cgd }
1131 1.13 cgd if (!first)
1132 1.153 christos (void)printf(" %s", memname);
1133 1.13 cgd first = 0;
1134 1.13 cgd }
1135 1.153 christos (void)putchar('\n');
1136 1.13 cgd }
1137 1.13 cgd
1138 1.1 cgd (void)printf(
1139 1.119 simonb "\nMemory statistics by type Type Kern\n");
1140 1.13 cgd (void)printf(
1141 1.148 simonb " Type InUse MemUse HighUse Limit Requests Limit Limit Size(s)\n");
1142 1.133 chs for (kread(namelist, X_KMEMSTAT, &ksp, sizeof(ksp));
1143 1.109 thorpej ksp != NULL; ksp = ks.ks_next) {
1144 1.109 thorpej deref_kptr(ksp, &ks, sizeof(ks), "malloc type");
1145 1.109 thorpej if (ks.ks_calls == 0)
1146 1.1 cgd continue;
1147 1.109 thorpej deref_kptr(ks.ks_shortdesc, memname,
1148 1.109 thorpej sizeof(memname), "malloc type name");
1149 1.148 simonb (void)printf("%14s%6ld%6ldK%7ldK%6ldK%10ld%5u%6u",
1150 1.109 thorpej memname,
1151 1.152 christos ks.ks_inuse, howmany(ks.ks_memuse, KILO),
1152 1.152 christos howmany(ks.ks_maxused, KILO),
1153 1.152 christos howmany(ks.ks_limit, KILO), ks.ks_calls,
1154 1.109 thorpej ks.ks_limblocks, ks.ks_mapblocks);
1155 1.13 cgd first = 1;
1156 1.13 cgd for (j = 1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1) {
1157 1.109 thorpej if ((ks.ks_size & j) == 0)
1158 1.13 cgd continue;
1159 1.13 cgd if (first)
1160 1.153 christos (void)printf(" %d", j);
1161 1.13 cgd else
1162 1.153 christos (void)printf(",%d", j);
1163 1.13 cgd first = 0;
1164 1.13 cgd }
1165 1.153 christos (void)printf("\n");
1166 1.109 thorpej totuse += ks.ks_memuse;
1167 1.109 thorpej totreq += ks.ks_calls;
1168 1.1 cgd }
1169 1.102 soren (void)printf("\nMemory totals: In Use Free Requests\n");
1170 1.102 soren (void)printf(" %7ldK %6ldK %8ld\n\n",
1171 1.152 christos howmany(totuse, KILO), howmany(totfree, KILO), totreq);
1172 1.51 pk }
1173 1.51 pk
1174 1.51 pk void
1175 1.126 simonb dopool(int verbose, int wide)
1176 1.51 pk {
1177 1.69 enami int first, ovflw;
1178 1.87 lukem void *addr;
1179 1.126 simonb long total, inuse, this_total, this_inuse;
1180 1.137 chs LIST_HEAD(,pool) pool_head;
1181 1.51 pk struct pool pool, *pp = &pool;
1182 1.98 christos struct pool_allocator pa;
1183 1.87 lukem char name[32], maxp[32];
1184 1.51 pk
1185 1.133 chs kread(namelist, X_POOLHEAD, &pool_head, sizeof(pool_head));
1186 1.137 chs addr = LIST_FIRST(&pool_head);
1187 1.51 pk
1188 1.126 simonb total = inuse = 0;
1189 1.126 simonb
1190 1.137 chs for (first = 1; addr != NULL; addr = LIST_NEXT(pp, pr_poollist) ) {
1191 1.87 lukem deref_kptr(addr, pp, sizeof(*pp), "pool chain trashed");
1192 1.98 christos deref_kptr(pp->pr_alloc, &pa, sizeof(pa),
1193 1.125 dsainty "pool allocator trashed");
1194 1.87 lukem deref_kptr(pp->pr_wchan, name, sizeof(name),
1195 1.98 christos "pool wait channel trashed");
1196 1.87 lukem name[sizeof(name)-1] = '\0';
1197 1.51 pk
1198 1.51 pk if (first) {
1199 1.51 pk (void)printf("Memory resource pool statistics\n");
1200 1.51 pk (void)printf(
1201 1.126 simonb "%-*s%*s%*s%5s%*s%s%s%*s%*s%6s%s%6s%6s%6s%5s%s%s\n",
1202 1.126 simonb wide ? 16 : 11, "Name",
1203 1.126 simonb wide ? 6 : 5, "Size",
1204 1.126 simonb wide ? 12 : 9, "Requests",
1205 1.75 enami "Fail",
1206 1.126 simonb wide ? 12 : 9, "Releases",
1207 1.148 simonb wide ? " InUse" : "",
1208 1.126 simonb wide ? " Avail" : "",
1209 1.126 simonb wide ? 7 : 6, "Pgreq",
1210 1.126 simonb wide ? 7 : 6, "Pgrel",
1211 1.75 enami "Npage",
1212 1.126 simonb wide ? " PageSz" : "",
1213 1.75 enami "Hiwat",
1214 1.75 enami "Minpg",
1215 1.75 enami "Maxpg",
1216 1.126 simonb "Idle",
1217 1.126 simonb wide ? " Flags" : "",
1218 1.126 simonb wide ? " Util" : "");
1219 1.51 pk first = 0;
1220 1.51 pk }
1221 1.113 dsl if (pp->pr_nget == 0 && !verbose)
1222 1.113 dsl continue;
1223 1.51 pk if (pp->pr_maxpages == UINT_MAX)
1224 1.153 christos (void)snprintf(maxp, sizeof(maxp), "inf");
1225 1.51 pk else
1226 1.153 christos (void)snprintf(maxp, sizeof(maxp), "%u",
1227 1.153 christos pp->pr_maxpages);
1228 1.69 enami ovflw = 0;
1229 1.126 simonb PRWORD(ovflw, "%-*s", wide ? 16 : 11, 0, name);
1230 1.126 simonb PRWORD(ovflw, " %*u", wide ? 6 : 5, 1, pp->pr_size);
1231 1.126 simonb PRWORD(ovflw, " %*lu", wide ? 12 : 9, 1, pp->pr_nget);
1232 1.69 enami PRWORD(ovflw, " %*lu", 5, 1, pp->pr_nfail);
1233 1.126 simonb PRWORD(ovflw, " %*lu", wide ? 12 : 9, 1, pp->pr_nput);
1234 1.126 simonb if (wide)
1235 1.148 simonb PRWORD(ovflw, " %*u", 7, 1, pp->pr_nout);
1236 1.126 simonb if (wide)
1237 1.126 simonb PRWORD(ovflw, " %*u", 6, 1, pp->pr_nitems);
1238 1.126 simonb PRWORD(ovflw, " %*lu", wide ? 7 : 6, 1, pp->pr_npagealloc);
1239 1.126 simonb PRWORD(ovflw, " %*lu", wide ? 7 : 6, 1, pp->pr_npagefree);
1240 1.126 simonb PRWORD(ovflw, " %*u", 6, 1, pp->pr_npages);
1241 1.126 simonb if (wide)
1242 1.126 simonb PRWORD(ovflw, " %*u", 7, 1, pa.pa_pagesz);
1243 1.126 simonb PRWORD(ovflw, " %*u", 6, 1, pp->pr_hiwat);
1244 1.126 simonb PRWORD(ovflw, " %*u", 6, 1, pp->pr_minpages);
1245 1.69 enami PRWORD(ovflw, " %*s", 6, 1, maxp);
1246 1.126 simonb PRWORD(ovflw, " %*lu", 5, 1, pp->pr_nidle);
1247 1.126 simonb if (wide)
1248 1.126 simonb PRWORD(ovflw, " 0x%0*x", 4, 1,
1249 1.126 simonb pp->pr_flags | pp->pr_roflags);
1250 1.51 pk
1251 1.126 simonb this_inuse = pp->pr_nout * pp->pr_size;
1252 1.126 simonb this_total = pp->pr_npages * pa.pa_pagesz;
1253 1.84 bjh21 if (pp->pr_roflags & PR_RECURSIVE) {
1254 1.84 bjh21 /*
1255 1.84 bjh21 * Don't count in-use memory, since it's part
1256 1.84 bjh21 * of another pool and will be accounted for
1257 1.84 bjh21 * there.
1258 1.84 bjh21 */
1259 1.126 simonb total += (this_total - this_inuse);
1260 1.84 bjh21 } else {
1261 1.126 simonb inuse += this_inuse;
1262 1.126 simonb total += this_total;
1263 1.84 bjh21 }
1264 1.126 simonb if (wide) {
1265 1.126 simonb if (this_total == 0)
1266 1.153 christos (void)printf(" ---");
1267 1.126 simonb else
1268 1.153 christos (void)printf(" %5.1f%%",
1269 1.126 simonb (100.0 * this_inuse) / this_total);
1270 1.126 simonb }
1271 1.153 christos (void)printf("\n");
1272 1.51 pk }
1273 1.51 pk
1274 1.152 christos inuse /= KILO;
1275 1.152 christos total /= KILO;
1276 1.153 christos (void)printf(
1277 1.153 christos "\nIn use %ldK, total allocated %ldK; utilization %.1f%%\n",
1278 1.126 simonb inuse, total, (100.0 * inuse) / total);
1279 1.1 cgd }
1280 1.96 enami
1281 1.96 enami void
1282 1.154 ad dopoolcache(void)
1283 1.96 enami {
1284 1.96 enami struct pool_cache pool_cache, *pc = &pool_cache;
1285 1.154 ad pool_cache_cpu_t cache_cpu, *cc = &cache_cpu;
1286 1.154 ad LIST_HEAD(,pool) pool_head;
1287 1.154 ad struct pool pool, *pp = &pool;
1288 1.154 ad char name[32];
1289 1.154 ad uint64_t cpuhit, cpumiss, tot;
1290 1.154 ad void *addr;
1291 1.154 ad int first, ovflw, i;
1292 1.154 ad double p;
1293 1.96 enami
1294 1.154 ad kread(namelist, X_POOLHEAD, &pool_head, sizeof(pool_head));
1295 1.154 ad addr = LIST_FIRST(&pool_head);
1296 1.96 enami
1297 1.154 ad for (first = 1; addr != NULL; addr = LIST_NEXT(pp, pr_poollist) ) {
1298 1.154 ad deref_kptr(addr, pp, sizeof(*pp), "pool chain trashed");
1299 1.154 ad if (pp->pr_cache == NULL)
1300 1.96 enami continue;
1301 1.154 ad deref_kptr(pp->pr_wchan, name, sizeof(name),
1302 1.154 ad "pool wait channel trashed");
1303 1.154 ad deref_kptr(pp->pr_cache, pc, sizeof(*pc), "pool cache trashed");
1304 1.154 ad name[sizeof(name)-1] = '\0';
1305 1.154 ad
1306 1.154 ad cpuhit = 0;
1307 1.154 ad cpumiss = 0;
1308 1.154 ad for (i = 0; i < sizeof(pc->pc_cpus) / sizeof(pc->pc_cpus[0]);
1309 1.154 ad i++) {
1310 1.154 ad if ((addr = pc->pc_cpus[i]) == NULL)
1311 1.154 ad continue;
1312 1.154 ad deref_kptr(addr, cc, sizeof(*cc),
1313 1.154 ad "pool cache cpu trashed");
1314 1.154 ad cpuhit += cc->cc_hits;
1315 1.154 ad cpumiss += cc->cc_misses;
1316 1.137 chs }
1317 1.154 ad
1318 1.154 ad if (first) {
1319 1.154 ad (void)printf("Pool cache statistics.\n");
1320 1.154 ad (void)printf("%-*s%*s%*s%*s%*s%*s%*s%*s%*s\n",
1321 1.154 ad 12, "Name",
1322 1.154 ad 6, "Spin",
1323 1.154 ad 6, "Full",
1324 1.154 ad 6, "Empty",
1325 1.154 ad 12, "PoolLayer",
1326 1.154 ad 12, "CacheLayer",
1327 1.154 ad 6, "Hit%",
1328 1.154 ad 12, "CpuLayer",
1329 1.154 ad 6, "Hit%"
1330 1.154 ad );
1331 1.154 ad first = 0;
1332 1.96 enami }
1333 1.154 ad
1334 1.154 ad ovflw = 0;
1335 1.154 ad PRWORD(ovflw, "%-*s", 13, 1, name);
1336 1.154 ad PRWORD(ovflw, " %*llu", 6, 1, (long long)pc->pc_contended);
1337 1.154 ad PRWORD(ovflw, " %*u", 6, 1, pc->pc_nfull);
1338 1.154 ad PRWORD(ovflw, " %*u", 6, 1, pc->pc_nempty);
1339 1.154 ad
1340 1.154 ad PRWORD(ovflw, " %*llu", 12, 1, (long long)pc->pc_misses);
1341 1.154 ad
1342 1.154 ad tot = pc->pc_hits + pc->pc_misses;
1343 1.154 ad p = pc->pc_hits * 100.0 / (tot);
1344 1.154 ad PRWORD(ovflw, " %*llu", 12, 1, (long long)tot);
1345 1.154 ad PRWORD(ovflw, " %*.1f", 6, 1, p);
1346 1.154 ad
1347 1.154 ad tot = cpuhit + cpumiss;
1348 1.154 ad p = cpuhit * 100.0 / (tot);
1349 1.154 ad PRWORD(ovflw, " %*llu", 12, 1, (long long)tot);
1350 1.154 ad PRWORD(ovflw, " %*.1f", 6, 1, p);
1351 1.154 ad printf("\n");
1352 1.96 enami }
1353 1.96 enami }
1354 1.90 lukem
1355 1.87 lukem enum hashtype { /* from <sys/systm.h> */
1356 1.87 lukem HASH_LIST,
1357 1.87 lukem HASH_TAILQ
1358 1.87 lukem };
1359 1.87 lukem
1360 1.87 lukem struct uidinfo { /* XXX: no kernel header file */
1361 1.87 lukem LIST_ENTRY(uidinfo) ui_hash;
1362 1.87 lukem uid_t ui_uid;
1363 1.87 lukem long ui_proccnt;
1364 1.87 lukem };
1365 1.87 lukem
1366 1.87 lukem struct kernel_hash {
1367 1.90 lukem const char * description; /* description */
1368 1.90 lukem int hashsize; /* nlist index for hash size */
1369 1.90 lukem int hashtbl; /* nlist index for hash table */
1370 1.90 lukem enum hashtype type; /* type of hash table */
1371 1.101 sommerfe size_t offset; /* offset of {LIST,TAILQ}_NEXT */
1372 1.87 lukem } khashes[] =
1373 1.87 lukem {
1374 1.87 lukem {
1375 1.90 lukem "buffer hash",
1376 1.90 lukem X_BUFHASH, X_BUFHASHTBL,
1377 1.90 lukem HASH_LIST, offsetof(struct buf, b_hash)
1378 1.90 lukem }, {
1379 1.90 lukem "inode cache (ihash)",
1380 1.87 lukem X_IHASH, X_IHASHTBL,
1381 1.87 lukem HASH_LIST, offsetof(struct inode, i_hash)
1382 1.90 lukem }, {
1383 1.90 lukem "ipv4 address -> interface hash",
1384 1.87 lukem X_IFADDRHASH, X_IFADDRHASHTBL,
1385 1.87 lukem HASH_LIST, offsetof(struct in_ifaddr, ia_hash),
1386 1.90 lukem }, {
1387 1.90 lukem "name cache hash",
1388 1.89 lukem X_NCHASH, X_NCHASHTBL,
1389 1.89 lukem HASH_LIST, offsetof(struct namecache, nc_hash),
1390 1.90 lukem }, {
1391 1.90 lukem "name cache directory hash",
1392 1.89 lukem X_NCVHASH, X_NCVHASHTBL,
1393 1.89 lukem HASH_LIST, offsetof(struct namecache, nc_vhash),
1394 1.90 lukem }, {
1395 1.90 lukem "nfs client node cache",
1396 1.90 lukem X_NFSNODE, X_NFSNODETBL,
1397 1.90 lukem HASH_LIST, offsetof(struct nfsnode, n_hash)
1398 1.90 lukem }, {
1399 1.90 lukem "user info (uid -> used processes) hash",
1400 1.90 lukem X_UIHASH, X_UIHASHTBL,
1401 1.90 lukem HASH_LIST, offsetof(struct uidinfo, ui_hash),
1402 1.90 lukem }, {
1403 1.90 lukem NULL, -1, -1, 0, 0,
1404 1.87 lukem }
1405 1.87 lukem };
1406 1.87 lukem
1407 1.87 lukem void
1408 1.88 lukem dohashstat(int verbose, int todo, const char *hashname)
1409 1.101 sommerfe {
1410 1.87 lukem LIST_HEAD(, generic) *hashtbl_list;
1411 1.87 lukem TAILQ_HEAD(, generic) *hashtbl_tailq;
1412 1.87 lukem struct kernel_hash *curhash;
1413 1.118 itojun void *hashaddr, *hashbuf, *nhashbuf, *nextaddr;
1414 1.87 lukem size_t elemsize, hashbufsize, thissize;
1415 1.87 lukem u_long hashsize;
1416 1.87 lukem int i, used, items, chain, maxchain;
1417 1.87 lukem
1418 1.87 lukem hashbuf = NULL;
1419 1.87 lukem hashbufsize = 0;
1420 1.88 lukem
1421 1.88 lukem if (todo & HASHLIST) {
1422 1.153 christos (void)printf("Supported hashes:\n");
1423 1.90 lukem for (curhash = khashes; curhash->description; curhash++) {
1424 1.101 sommerfe if (hashnl[curhash->hashsize].n_value == 0 ||
1425 1.90 lukem hashnl[curhash->hashtbl].n_value == 0)
1426 1.90 lukem continue;
1427 1.153 christos (void)printf("\t%-16s%s\n",
1428 1.90 lukem hashnl[curhash->hashsize].n_name + 1,
1429 1.90 lukem curhash->description);
1430 1.88 lukem }
1431 1.88 lukem return;
1432 1.88 lukem }
1433 1.88 lukem
1434 1.88 lukem if (hashname != NULL) {
1435 1.90 lukem for (curhash = khashes; curhash->description; curhash++) {
1436 1.90 lukem if (strcmp(hashnl[curhash->hashsize].n_name + 1,
1437 1.90 lukem hashname) == 0 &&
1438 1.101 sommerfe hashnl[curhash->hashsize].n_value != 0 &&
1439 1.90 lukem hashnl[curhash->hashtbl].n_value != 0)
1440 1.88 lukem break;
1441 1.88 lukem }
1442 1.90 lukem if (curhash->description == NULL) {
1443 1.90 lukem warnx("%s: no such hash", hashname);
1444 1.90 lukem return;
1445 1.90 lukem }
1446 1.88 lukem }
1447 1.88 lukem
1448 1.153 christos (void)printf(
1449 1.88 lukem "%-16s %8s %8s %8s %8s %8s %8s\n"
1450 1.88 lukem "%-16s %8s %8s %8s %8s %8s %8s\n",
1451 1.88 lukem "", "total", "used", "util", "num", "average", "maximum",
1452 1.88 lukem "hash table", "buckets", "buckets", "%", "items", "chain",
1453 1.88 lukem "chain");
1454 1.87 lukem
1455 1.90 lukem for (curhash = khashes; curhash->description; curhash++) {
1456 1.101 sommerfe if (hashnl[curhash->hashsize].n_value == 0 ||
1457 1.90 lukem hashnl[curhash->hashtbl].n_value == 0)
1458 1.90 lukem continue;
1459 1.88 lukem if (hashname != NULL &&
1460 1.90 lukem strcmp(hashnl[curhash->hashsize].n_name + 1, hashname))
1461 1.88 lukem continue;
1462 1.87 lukem elemsize = curhash->type == HASH_LIST ?
1463 1.87 lukem sizeof(*hashtbl_list) : sizeof(*hashtbl_tailq);
1464 1.90 lukem deref_kptr((void *)hashnl[curhash->hashsize].n_value,
1465 1.90 lukem &hashsize, sizeof(hashsize),
1466 1.90 lukem hashnl[curhash->hashsize].n_name);
1467 1.87 lukem hashsize++;
1468 1.90 lukem deref_kptr((void *)hashnl[curhash->hashtbl].n_value,
1469 1.90 lukem &hashaddr, sizeof(hashaddr),
1470 1.90 lukem hashnl[curhash->hashtbl].n_name);
1471 1.87 lukem if (verbose)
1472 1.153 christos (void)printf(
1473 1.153 christos "%s %lu, %s %p, offset %ld, elemsize %llu\n",
1474 1.90 lukem hashnl[curhash->hashsize].n_name + 1, hashsize,
1475 1.90 lukem hashnl[curhash->hashtbl].n_name + 1, hashaddr,
1476 1.101 sommerfe (long)curhash->offset,
1477 1.91 jmc (unsigned long long)elemsize);
1478 1.87 lukem thissize = hashsize * elemsize;
1479 1.144 christos if (hashbuf == NULL || thissize > hashbufsize) {
1480 1.118 itojun if ((nhashbuf = realloc(hashbuf, thissize)) == NULL)
1481 1.101 sommerfe errx(1, "malloc hashbuf %llu",
1482 1.91 jmc (unsigned long long)hashbufsize);
1483 1.118 itojun hashbuf = nhashbuf;
1484 1.118 itojun hashbufsize = thissize;
1485 1.87 lukem }
1486 1.87 lukem deref_kptr(hashaddr, hashbuf, thissize,
1487 1.90 lukem hashnl[curhash->hashtbl].n_name);
1488 1.87 lukem used = 0;
1489 1.87 lukem items = maxchain = 0;
1490 1.135 lukem if (curhash->type == HASH_LIST) {
1491 1.87 lukem hashtbl_list = hashbuf;
1492 1.135 lukem hashtbl_tailq = NULL;
1493 1.135 lukem } else {
1494 1.135 lukem hashtbl_list = NULL;
1495 1.87 lukem hashtbl_tailq = hashbuf;
1496 1.135 lukem }
1497 1.87 lukem for (i = 0; i < hashsize; i++) {
1498 1.87 lukem if (curhash->type == HASH_LIST)
1499 1.87 lukem nextaddr = LIST_FIRST(&hashtbl_list[i]);
1500 1.87 lukem else
1501 1.87 lukem nextaddr = TAILQ_FIRST(&hashtbl_tailq[i]);
1502 1.87 lukem if (nextaddr == NULL)
1503 1.87 lukem continue;
1504 1.87 lukem if (verbose)
1505 1.153 christos (void)printf("%5d: %p\n", i, nextaddr);
1506 1.87 lukem used++;
1507 1.87 lukem chain = 0;
1508 1.87 lukem do {
1509 1.87 lukem chain++;
1510 1.87 lukem deref_kptr((char *)nextaddr + curhash->offset,
1511 1.87 lukem &nextaddr, sizeof(void *),
1512 1.87 lukem "hash chain corrupted");
1513 1.87 lukem if (verbose > 1)
1514 1.153 christos (void)printf("got nextaddr as %p\n",
1515 1.87 lukem nextaddr);
1516 1.87 lukem } while (nextaddr != NULL);
1517 1.87 lukem items += chain;
1518 1.87 lukem if (verbose && chain > 1)
1519 1.153 christos (void)printf("\tchain = %d\n", chain);
1520 1.87 lukem if (chain > maxchain)
1521 1.87 lukem maxchain = chain;
1522 1.87 lukem }
1523 1.153 christos (void)printf("%-16s %8ld %8d %8.2f %8d %8.2f %8d\n",
1524 1.90 lukem hashnl[curhash->hashsize].n_name + 1,
1525 1.87 lukem hashsize, used, used * 100.0 / hashsize,
1526 1.93 lukem items, used ? (double)items / used : 0.0, maxchain);
1527 1.87 lukem }
1528 1.87 lukem }
1529 1.87 lukem
1530 1.1 cgd /*
1531 1.147 kardel * kreadc like kread but returns 1 if sucessful, 0 otherwise
1532 1.147 kardel */
1533 1.147 kardel int
1534 1.147 kardel kreadc(struct nlist *nl, int nlx, void *addr, size_t size)
1535 1.147 kardel {
1536 1.147 kardel const char *sym;
1537 1.147 kardel
1538 1.147 kardel sym = nl[nlx].n_name;
1539 1.147 kardel if (*sym == '_')
1540 1.147 kardel ++sym;
1541 1.147 kardel if (nl[nlx].n_type == 0 || nl[nlx].n_value == 0)
1542 1.147 kardel return 0;
1543 1.147 kardel deref_kptr((void *)nl[nlx].n_value, addr, size, sym);
1544 1.147 kardel return 1;
1545 1.147 kardel }
1546 1.147 kardel
1547 1.147 kardel /*
1548 1.90 lukem * kread reads something from the kernel, given its nlist index in namelist[].
1549 1.1 cgd */
1550 1.1 cgd void
1551 1.133 chs kread(struct nlist *nl, int nlx, void *addr, size_t size)
1552 1.1 cgd {
1553 1.50 mycroft const char *sym;
1554 1.1 cgd
1555 1.133 chs sym = nl[nlx].n_name;
1556 1.87 lukem if (*sym == '_')
1557 1.87 lukem ++sym;
1558 1.133 chs if (nl[nlx].n_type == 0 || nl[nlx].n_value == 0)
1559 1.87 lukem errx(1, "symbol %s not defined", sym);
1560 1.133 chs deref_kptr((void *)nl[nlx].n_value, addr, size, sym);
1561 1.87 lukem }
1562 1.87 lukem
1563 1.87 lukem /*
1564 1.101 sommerfe * Dereference the kernel pointer `kptr' and fill in the local copy
1565 1.87 lukem * pointed to by `ptr'. The storage space must be pre-allocated,
1566 1.87 lukem * and the size of the copy passed in `len'.
1567 1.87 lukem */
1568 1.87 lukem void
1569 1.87 lukem deref_kptr(const void *kptr, void *ptr, size_t len, const char *msg)
1570 1.87 lukem {
1571 1.87 lukem
1572 1.87 lukem if (*msg == '_')
1573 1.87 lukem msg++;
1574 1.87 lukem if (kvm_read(kd, (u_long)kptr, (char *)ptr, len) != len)
1575 1.87 lukem errx(1, "kptr %lx: %s: %s", (u_long)kptr, msg, kvm_geterr(kd));
1576 1.1 cgd }
1577 1.1 cgd
1578 1.45 thorpej /*
1579 1.45 thorpej * Traverse the UVM history buffers, performing the requested action.
1580 1.45 thorpej *
1581 1.45 thorpej * Note, we assume that if we're not listing, we're dumping.
1582 1.45 thorpej */
1583 1.45 thorpej void
1584 1.73 simonb hist_traverse(int todo, const char *histname)
1585 1.45 thorpej {
1586 1.45 thorpej struct uvm_history_head histhead;
1587 1.45 thorpej struct uvm_history hist, *histkva;
1588 1.45 thorpej char *name = NULL;
1589 1.45 thorpej size_t namelen = 0;
1590 1.45 thorpej
1591 1.90 lukem if (histnl[0].n_value == 0) {
1592 1.87 lukem warnx("UVM history is not compiled into the kernel.");
1593 1.45 thorpej return;
1594 1.45 thorpej }
1595 1.45 thorpej
1596 1.87 lukem deref_kptr((void *)histnl[X_UVM_HISTORIES].n_value, &histhead,
1597 1.87 lukem sizeof(histhead), histnl[X_UVM_HISTORIES].n_name);
1598 1.45 thorpej
1599 1.45 thorpej if (histhead.lh_first == NULL) {
1600 1.87 lukem warnx("No active UVM history logs.");
1601 1.45 thorpej return;
1602 1.45 thorpej }
1603 1.45 thorpej
1604 1.45 thorpej if (todo & HISTLIST)
1605 1.153 christos (void)printf("Active UVM histories:");
1606 1.45 thorpej
1607 1.75 enami for (histkva = LIST_FIRST(&histhead); histkva != NULL;
1608 1.75 enami histkva = LIST_NEXT(&hist, list)) {
1609 1.87 lukem deref_kptr(histkva, &hist, sizeof(hist), "histkva");
1610 1.142 christos if (name == NULL || hist.namelen > namelen) {
1611 1.45 thorpej if (name != NULL)
1612 1.45 thorpej free(name);
1613 1.45 thorpej namelen = hist.namelen;
1614 1.45 thorpej if ((name = malloc(namelen + 1)) == NULL)
1615 1.45 thorpej err(1, "malloc history name");
1616 1.45 thorpej }
1617 1.45 thorpej
1618 1.87 lukem deref_kptr(hist.name, name, namelen, "history name");
1619 1.45 thorpej name[namelen] = '\0';
1620 1.45 thorpej if (todo & HISTLIST)
1621 1.153 christos (void)printf(" %s", name);
1622 1.45 thorpej else {
1623 1.45 thorpej /*
1624 1.45 thorpej * If we're dumping all histories, do it, else
1625 1.45 thorpej * check to see if this is the one we want.
1626 1.45 thorpej */
1627 1.45 thorpej if (histname == NULL || strcmp(histname, name) == 0) {
1628 1.45 thorpej if (histname == NULL)
1629 1.153 christos (void)printf(
1630 1.153 christos "\nUVM history `%s':\n", name);
1631 1.45 thorpej hist_dodump(&hist);
1632 1.45 thorpej }
1633 1.45 thorpej }
1634 1.45 thorpej }
1635 1.45 thorpej
1636 1.45 thorpej if (todo & HISTLIST)
1637 1.153 christos (void)putchar('\n');
1638 1.45 thorpej
1639 1.45 thorpej if (name != NULL)
1640 1.45 thorpej free(name);
1641 1.45 thorpej }
1642 1.45 thorpej
1643 1.45 thorpej /*
1644 1.45 thorpej * Actually dump the history buffer at the specified KVA.
1645 1.45 thorpej */
1646 1.45 thorpej void
1647 1.73 simonb hist_dodump(struct uvm_history *histp)
1648 1.45 thorpej {
1649 1.45 thorpej struct uvm_history_ent *histents, *e;
1650 1.45 thorpej size_t histsize;
1651 1.45 thorpej char *fmt = NULL, *fn = NULL;
1652 1.45 thorpej size_t fmtlen = 0, fnlen = 0;
1653 1.45 thorpej int i;
1654 1.45 thorpej
1655 1.45 thorpej histsize = sizeof(struct uvm_history_ent) * histp->n;
1656 1.45 thorpej
1657 1.45 thorpej if ((histents = malloc(histsize)) == NULL)
1658 1.45 thorpej err(1, "malloc history entries");
1659 1.45 thorpej
1660 1.153 christos (void)memset(histents, 0, histsize);
1661 1.45 thorpej
1662 1.87 lukem deref_kptr(histp->e, histents, histsize, "history entries");
1663 1.45 thorpej i = histp->f;
1664 1.45 thorpej do {
1665 1.45 thorpej e = &histents[i];
1666 1.45 thorpej if (e->fmt != NULL) {
1667 1.143 christos if (fmt == NULL || e->fmtlen > fmtlen) {
1668 1.45 thorpej if (fmt != NULL)
1669 1.45 thorpej free(fmt);
1670 1.45 thorpej fmtlen = e->fmtlen;
1671 1.45 thorpej if ((fmt = malloc(fmtlen + 1)) == NULL)
1672 1.45 thorpej err(1, "malloc printf format");
1673 1.45 thorpej }
1674 1.143 christos if (fn == NULL || e->fnlen > fnlen) {
1675 1.45 thorpej if (fn != NULL)
1676 1.45 thorpej free(fn);
1677 1.45 thorpej fnlen = e->fnlen;
1678 1.45 thorpej if ((fn = malloc(fnlen + 1)) == NULL)
1679 1.45 thorpej err(1, "malloc function name");
1680 1.45 thorpej }
1681 1.45 thorpej
1682 1.87 lukem deref_kptr(e->fmt, fmt, fmtlen, "printf format");
1683 1.45 thorpej fmt[fmtlen] = '\0';
1684 1.45 thorpej
1685 1.87 lukem deref_kptr(e->fn, fn, fnlen, "function name");
1686 1.45 thorpej fn[fnlen] = '\0';
1687 1.45 thorpej
1688 1.153 christos (void)printf("%06ld.%06ld ", (long int)e->tv.tv_sec,
1689 1.61 kleink (long int)e->tv.tv_usec);
1690 1.153 christos (void)printf("%s#%ld: ", fn, e->call);
1691 1.153 christos (void)printf(fmt, e->v[0], e->v[1], e->v[2], e->v[3]);
1692 1.153 christos (void)putchar('\n');
1693 1.45 thorpej }
1694 1.45 thorpej i = (i + 1) % histp->n;
1695 1.45 thorpej } while (i != histp->f);
1696 1.45 thorpej
1697 1.45 thorpej free(histents);
1698 1.45 thorpej if (fmt != NULL)
1699 1.45 thorpej free(fmt);
1700 1.45 thorpej if (fn != NULL)
1701 1.45 thorpej free(fn);
1702 1.45 thorpej }
1703 1.45 thorpej
1704 1.1 cgd void
1705 1.73 simonb usage(void)
1706 1.1 cgd {
1707 1.47 mrg
1708 1.1 cgd (void)fprintf(stderr,
1709 1.155 yamt "usage: %s [-CefHiLlmstUvW] [-c count] [-h hashname] [-M core] [-N system]\n"
1710 1.127 wiz "\t\t[-u histname] [-w wait] [disks]\n", getprogname());
1711 1.1 cgd exit(1);
1712 1.1 cgd }
1713