vmstat.c revision 1.125 1 1.125 dsainty /* $NetBSD: vmstat.c,v 1.125 2004/12/20 08:20:50 dsainty Exp $ */
2 1.45 thorpej
3 1.45 thorpej /*-
4 1.87 lukem * Copyright (c) 1998, 2000, 2001 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.125 dsainty __RCSID("$NetBSD: vmstat.c,v 1.125 2004/12/20 08:20:50 dsainty 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.87 lukem #include <sys/device.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.29 thorpej #include "dkstats.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.1 cgd { "_boottime" },
144 1.75 enami #define X_HZ 1
145 1.1 cgd { "_hz" },
146 1.75 enami #define X_STATHZ 2
147 1.13 cgd { "_stathz" },
148 1.75 enami #define X_NCHSTATS 3
149 1.1 cgd { "_nchstats" },
150 1.65 itojun #define X_INTRNAMES 4
151 1.1 cgd { "_intrnames" },
152 1.65 itojun #define X_EINTRNAMES 5
153 1.1 cgd { "_eintrnames" },
154 1.65 itojun #define X_INTRCNT 6
155 1.1 cgd { "_intrcnt" },
156 1.65 itojun #define X_EINTRCNT 7
157 1.1 cgd { "_eintrcnt" },
158 1.65 itojun #define X_KMEMSTAT 8
159 1.109 thorpej { "_kmemstatistics" },
160 1.65 itojun #define X_KMEMBUCKETS 9
161 1.1 cgd { "_bucket" },
162 1.75 enami #define X_ALLEVENTS 10
163 1.18 pk { "_allevents" },
164 1.75 enami #define X_POOLHEAD 11
165 1.51 pk { "_pool_head" },
166 1.65 itojun #define X_UVMEXP 12
167 1.58 thorpej { "_uvmexp" },
168 1.105 nathanw #define X_TIME 13
169 1.105 nathanw { "_time" },
170 1.105 nathanw #define X_END 14
171 1.90 lukem { NULL },
172 1.90 lukem };
173 1.90 lukem
174 1.90 lukem /*
175 1.90 lukem * Namelist for hash statistics
176 1.90 lukem */
177 1.90 lukem struct nlist hashnl[] =
178 1.90 lukem {
179 1.90 lukem #define X_NFSNODE 0
180 1.87 lukem { "_nfsnodehash" },
181 1.90 lukem #define X_NFSNODETBL 1
182 1.87 lukem { "_nfsnodehashtbl" },
183 1.90 lukem #define X_IHASH 2
184 1.87 lukem { "_ihash" },
185 1.90 lukem #define X_IHASHTBL 3
186 1.87 lukem { "_ihashtbl" },
187 1.90 lukem #define X_BUFHASH 4
188 1.87 lukem { "_bufhash" },
189 1.90 lukem #define X_BUFHASHTBL 5
190 1.87 lukem { "_bufhashtbl" },
191 1.122 junyoung #define X_UIHASH 6
192 1.87 lukem { "_uihash" },
193 1.122 junyoung #define X_UIHASHTBL 7
194 1.87 lukem { "_uihashtbl" },
195 1.122 junyoung #define X_IFADDRHASH 8
196 1.87 lukem { "_in_ifaddrhash" },
197 1.122 junyoung #define X_IFADDRHASHTBL 9
198 1.87 lukem { "_in_ifaddrhashtbl" },
199 1.122 junyoung #define X_NCHASH 10
200 1.89 lukem { "_nchash" },
201 1.122 junyoung #define X_NCHASHTBL 11
202 1.89 lukem { "_nchashtbl" },
203 1.122 junyoung #define X_NCVHASH 12
204 1.89 lukem { "_ncvhash" },
205 1.122 junyoung #define X_NCVHASHTBL 13
206 1.89 lukem { "_ncvhashtbl" },
207 1.122 junyoung #define X_HASHNL_SIZE 14 /* must be last */
208 1.90 lukem { NULL },
209 1.90 lukem };
210 1.87 lukem
211 1.90 lukem /*
212 1.90 lukem * Namelist for UVM histories
213 1.90 lukem */
214 1.90 lukem struct nlist histnl[] =
215 1.90 lukem {
216 1.90 lukem { "_uvm_histories" },
217 1.90 lukem #define X_UVM_HISTORIES 0
218 1.90 lukem { NULL },
219 1.1 cgd };
220 1.1 cgd
221 1.87 lukem
222 1.90 lukem
223 1.41 mrg struct uvmexp uvmexp, ouvmexp;
224 1.73 simonb int ndrives;
225 1.1 cgd
226 1.1 cgd int winlines = 20;
227 1.1 cgd
228 1.13 cgd kvm_t *kd;
229 1.13 cgd
230 1.87 lukem #define FORKSTAT 1<<0
231 1.87 lukem #define INTRSTAT 1<<1
232 1.87 lukem #define MEMSTAT 1<<2
233 1.87 lukem #define SUMSTAT 1<<3
234 1.87 lukem #define EVCNTSTAT 1<<4
235 1.87 lukem #define VMSTAT 1<<5
236 1.87 lukem #define HISTLIST 1<<6
237 1.87 lukem #define HISTDUMP 1<<7
238 1.87 lukem #define HASHSTAT 1<<8
239 1.88 lukem #define HASHLIST 1<<9
240 1.1 cgd
241 1.73 simonb void cpustats(void);
242 1.87 lukem void deref_kptr(const void *, void *, size_t, const char *);
243 1.73 simonb void dkstats(void);
244 1.73 simonb void doevcnt(int verbose);
245 1.88 lukem void dohashstat(int, int, const char *);
246 1.73 simonb void dointr(int verbose);
247 1.73 simonb void domem(void);
248 1.96 enami void dopool(int);
249 1.96 enami void dopoolcache(struct pool *, int);
250 1.73 simonb void dosum(void);
251 1.103 mycroft void dovmstat(struct timespec *, int);
252 1.73 simonb void kread(int, void *, size_t);
253 1.73 simonb void needhdr(int);
254 1.73 simonb long getuptime(void);
255 1.73 simonb void printhdr(void);
256 1.73 simonb long pct(long, long);
257 1.73 simonb void usage(void);
258 1.73 simonb void doforkst(void);
259 1.73 simonb
260 1.73 simonb void hist_traverse(int, const char *);
261 1.73 simonb void hist_dodump(struct uvm_history *);
262 1.73 simonb
263 1.73 simonb int main(int, char **);
264 1.73 simonb char **choosedrives(char **);
265 1.38 mrg
266 1.29 thorpej /* Namelist and memory file names. */
267 1.29 thorpej char *nlistf, *memf;
268 1.29 thorpej
269 1.47 mrg /* allow old usage [vmstat 1] */
270 1.47 mrg #define BACKWARD_COMPATIBILITY
271 1.47 mrg
272 1.38 mrg int
273 1.75 enami main(int argc, char *argv[])
274 1.1 cgd {
275 1.66 cgd int c, todo, verbose;
276 1.103 mycroft struct timespec interval;
277 1.1 cgd int reps;
278 1.75 enami char errbuf[_POSIX2_LINE_MAX];
279 1.75 enami gid_t egid = getegid();
280 1.88 lukem const char *histname, *hashname;
281 1.1 cgd
282 1.88 lukem histname = hashname = NULL;
283 1.48 mrg (void)setegid(getgid());
284 1.13 cgd memf = nlistf = NULL;
285 1.103 mycroft reps = todo = verbose = 0;
286 1.103 mycroft interval.tv_sec = 0;
287 1.103 mycroft interval.tv_nsec = 0;
288 1.108 atatat while ((c = getopt(argc, argv, "c:efh:HilLM:mN:su:Uvw:")) != -1) {
289 1.1 cgd switch (c) {
290 1.1 cgd case 'c':
291 1.1 cgd reps = atoi(optarg);
292 1.1 cgd break;
293 1.66 cgd case 'e':
294 1.66 cgd todo |= EVCNTSTAT;
295 1.66 cgd break;
296 1.1 cgd case 'f':
297 1.1 cgd todo |= FORKSTAT;
298 1.1 cgd break;
299 1.45 thorpej case 'h':
300 1.88 lukem hashname = optarg;
301 1.88 lukem /* FALLTHROUGH */
302 1.88 lukem case 'H':
303 1.87 lukem todo |= HASHSTAT;
304 1.45 thorpej break;
305 1.1 cgd case 'i':
306 1.1 cgd todo |= INTRSTAT;
307 1.1 cgd break;
308 1.45 thorpej case 'l':
309 1.45 thorpej todo |= HISTLIST;
310 1.45 thorpej break;
311 1.88 lukem case 'L':
312 1.88 lukem todo |= HASHLIST;
313 1.88 lukem break;
314 1.1 cgd case 'M':
315 1.13 cgd memf = optarg;
316 1.1 cgd break;
317 1.1 cgd case 'm':
318 1.1 cgd todo |= MEMSTAT;
319 1.1 cgd break;
320 1.1 cgd case 'N':
321 1.13 cgd nlistf = optarg;
322 1.1 cgd break;
323 1.1 cgd case 's':
324 1.1 cgd todo |= SUMSTAT;
325 1.1 cgd break;
326 1.87 lukem case 'u':
327 1.87 lukem histname = optarg;
328 1.87 lukem /* FALLTHROUGH */
329 1.87 lukem case 'U':
330 1.87 lukem todo |= HISTDUMP;
331 1.87 lukem break;
332 1.66 cgd case 'v':
333 1.87 lukem verbose++;
334 1.66 cgd break;
335 1.1 cgd case 'w':
336 1.103 mycroft interval.tv_sec = atol(optarg);
337 1.1 cgd break;
338 1.1 cgd case '?':
339 1.1 cgd default:
340 1.1 cgd usage();
341 1.1 cgd }
342 1.1 cgd }
343 1.1 cgd argc -= optind;
344 1.1 cgd argv += optind;
345 1.1 cgd
346 1.1 cgd if (todo == 0)
347 1.1 cgd todo = VMSTAT;
348 1.1 cgd
349 1.13 cgd /*
350 1.48 mrg * Discard setgid privileges. If not the running kernel, we toss
351 1.48 mrg * them away totally so that bad guys can't print interesting stuff
352 1.48 mrg * from kernel memory, otherwise switch back to kmem for the
353 1.48 mrg * duration of the kvm_openfiles() call.
354 1.13 cgd */
355 1.13 cgd if (nlistf != NULL || memf != NULL)
356 1.48 mrg (void)setgid(getgid());
357 1.48 mrg else
358 1.48 mrg (void)setegid(egid);
359 1.13 cgd
360 1.75 enami kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
361 1.75 enami if (kd == NULL)
362 1.87 lukem errx(1, "kvm_openfiles: %s", errbuf);
363 1.48 mrg
364 1.95 simonb if (nlistf == NULL && memf == NULL)
365 1.95 simonb (void)setgid(getgid());
366 1.1 cgd
367 1.13 cgd if ((c = kvm_nlist(kd, namelist)) != 0) {
368 1.90 lukem if (c == -1)
369 1.90 lukem errx(1, "kvm_nlist: %s %s", "namelist", kvm_geterr(kd));
370 1.90 lukem (void)fprintf(stderr, "vmstat: undefined symbols:");
371 1.110 matt for (c = 0; c < sizeof(namelist) / sizeof(namelist[0])-1; c++)
372 1.90 lukem if (namelist[c].n_type == 0)
373 1.90 lukem fprintf(stderr, " %s", namelist[c].n_name);
374 1.90 lukem (void)fputc('\n', stderr);
375 1.1 cgd exit(1);
376 1.1 cgd }
377 1.90 lukem if ((c = kvm_nlist(kd, hashnl)) == -1 || c == X_HASHNL_SIZE)
378 1.90 lukem errx(1, "kvm_nlist: %s %s", "hashnl", kvm_geterr(kd));
379 1.90 lukem if (kvm_nlist(kd, histnl) == -1)
380 1.90 lukem errx(1, "kvm_nlist: %s %s", "histnl", kvm_geterr(kd));
381 1.1 cgd
382 1.1 cgd if (todo & VMSTAT) {
383 1.1 cgd struct winsize winsize;
384 1.1 cgd
385 1.95 simonb dkinit(0); /* Initialize disk stats, no disks selected. */
386 1.49 drochner
387 1.49 drochner (void)setgid(getgid()); /* don't need privs anymore */
388 1.49 drochner
389 1.29 thorpej argv = choosedrives(argv); /* Select disks. */
390 1.1 cgd winsize.ws_row = 0;
391 1.115 simonb (void)ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize);
392 1.1 cgd if (winsize.ws_row > 0)
393 1.1 cgd winlines = winsize.ws_row;
394 1.1 cgd
395 1.1 cgd }
396 1.1 cgd
397 1.1 cgd #ifdef BACKWARD_COMPATIBILITY
398 1.1 cgd if (*argv) {
399 1.103 mycroft interval.tv_sec = atol(*argv);
400 1.1 cgd if (*++argv)
401 1.1 cgd reps = atoi(*argv);
402 1.1 cgd }
403 1.1 cgd #endif
404 1.1 cgd
405 1.103 mycroft if (interval.tv_sec) {
406 1.1 cgd if (!reps)
407 1.1 cgd reps = -1;
408 1.1 cgd } else if (reps)
409 1.103 mycroft interval.tv_sec = 1;
410 1.1 cgd
411 1.78 jhawk
412 1.78 jhawk /*
413 1.78 jhawk * Statistics dumping is incompatible with the default
414 1.78 jhawk * VMSTAT/dovmstat() output. So perform the interval/reps handling
415 1.78 jhawk * for it here.
416 1.78 jhawk */
417 1.87 lukem if ((todo & VMSTAT) == 0) {
418 1.99 enami for (;;) {
419 1.99 enami if (todo & (HISTLIST|HISTDUMP)) {
420 1.99 enami if ((todo & (HISTLIST|HISTDUMP)) ==
421 1.99 enami (HISTLIST|HISTDUMP))
422 1.99 enami errx(1, "you may list or dump,"
423 1.99 enami " but not both!");
424 1.99 enami hist_traverse(todo, histname);
425 1.99 enami putchar('\n');
426 1.99 enami }
427 1.99 enami if (todo & FORKSTAT) {
428 1.99 enami doforkst();
429 1.99 enami putchar('\n');
430 1.99 enami }
431 1.99 enami if (todo & MEMSTAT) {
432 1.99 enami domem();
433 1.99 enami dopool(verbose);
434 1.99 enami putchar('\n');
435 1.99 enami }
436 1.99 enami if (todo & SUMSTAT) {
437 1.99 enami dosum();
438 1.99 enami putchar('\n');
439 1.99 enami }
440 1.99 enami if (todo & INTRSTAT) {
441 1.99 enami dointr(verbose);
442 1.99 enami putchar('\n');
443 1.99 enami }
444 1.99 enami if (todo & EVCNTSTAT) {
445 1.99 enami doevcnt(verbose);
446 1.99 enami putchar('\n');
447 1.99 enami }
448 1.99 enami if (todo & (HASHLIST|HASHSTAT)) {
449 1.99 enami if ((todo & (HASHLIST|HASHSTAT)) ==
450 1.99 enami (HASHLIST|HASHSTAT))
451 1.99 enami errx(1, "you may list or display,"
452 1.99 enami " but not both!");
453 1.99 enami dohashstat(verbose, todo, hashname);
454 1.99 enami putchar('\n');
455 1.99 enami }
456 1.101 sommerfe
457 1.101 sommerfe if (reps >= 0 && --reps <=0)
458 1.99 enami break;
459 1.103 mycroft nanosleep(&interval, NULL);
460 1.87 lukem }
461 1.87 lukem } else
462 1.103 mycroft dovmstat(&interval, reps);
463 1.1 cgd exit(0);
464 1.1 cgd }
465 1.1 cgd
466 1.1 cgd char **
467 1.73 simonb choosedrives(char **argv)
468 1.1 cgd {
469 1.38 mrg int i;
470 1.1 cgd
471 1.1 cgd /*
472 1.1 cgd * Choose drives to be displayed. Priority goes to (in order) drives
473 1.1 cgd * supplied as arguments, default drives. If everything isn't filled
474 1.1 cgd * in and there are drives not taken care of, display the first few
475 1.1 cgd * that fit.
476 1.1 cgd */
477 1.75 enami #define BACKWARD_COMPATIBILITY
478 1.1 cgd for (ndrives = 0; *argv; ++argv) {
479 1.1 cgd #ifdef BACKWARD_COMPATIBILITY
480 1.124 dsl if (isdigit((unsigned char)**argv))
481 1.1 cgd break;
482 1.1 cgd #endif
483 1.1 cgd for (i = 0; i < dk_ndrive; i++) {
484 1.1 cgd if (strcmp(dr_name[i], *argv))
485 1.1 cgd continue;
486 1.29 thorpej dk_select[i] = 1;
487 1.1 cgd ++ndrives;
488 1.1 cgd break;
489 1.1 cgd }
490 1.1 cgd }
491 1.120 dbj for (i = 0; i < dk_ndrive && ndrives < 3; i++) {
492 1.29 thorpej if (dk_select[i])
493 1.1 cgd continue;
494 1.29 thorpej dk_select[i] = 1;
495 1.1 cgd ++ndrives;
496 1.1 cgd }
497 1.75 enami return (argv);
498 1.1 cgd }
499 1.1 cgd
500 1.1 cgd long
501 1.73 simonb getuptime(void)
502 1.1 cgd {
503 1.30 cgd static struct timeval boottime;
504 1.105 nathanw struct timeval now, diff;
505 1.1 cgd time_t uptime;
506 1.1 cgd
507 1.30 cgd if (boottime.tv_sec == 0)
508 1.1 cgd kread(X_BOOTTIME, &boottime, sizeof(boottime));
509 1.105 nathanw kread(X_TIME, &now, sizeof(now));
510 1.105 nathanw timersub(&now, &boottime, &diff);
511 1.105 nathanw uptime = diff.tv_sec;
512 1.87 lukem if (uptime <= 0 || uptime > 60*60*24*365*10)
513 1.87 lukem errx(1, "time makes no sense; namelist must be wrong.");
514 1.75 enami return (uptime);
515 1.1 cgd }
516 1.1 cgd
517 1.1 cgd int hz, hdrcnt;
518 1.1 cgd
519 1.1 cgd void
520 1.103 mycroft dovmstat(struct timespec *interval, int reps)
521 1.1 cgd {
522 1.1 cgd struct vmtotal total;
523 1.1 cgd time_t uptime, halfuptime;
524 1.17 cgd int mib[2];
525 1.17 cgd size_t size;
526 1.41 mrg int pagesize = getpagesize();
527 1.1 cgd
528 1.1 cgd uptime = getuptime();
529 1.1 cgd halfuptime = uptime / 2;
530 1.1 cgd (void)signal(SIGCONT, needhdr);
531 1.1 cgd
532 1.13 cgd if (namelist[X_STATHZ].n_type != 0 && namelist[X_STATHZ].n_value != 0)
533 1.13 cgd kread(X_STATHZ, &hz, sizeof(hz));
534 1.1 cgd if (!hz)
535 1.1 cgd kread(X_HZ, &hz, sizeof(hz));
536 1.1 cgd
537 1.1 cgd for (hdrcnt = 1;;) {
538 1.1 cgd if (!--hdrcnt)
539 1.1 cgd printhdr();
540 1.29 thorpej /* Read new disk statistics */
541 1.29 thorpej dkreadstats();
542 1.58 thorpej kread(X_UVMEXP, &uvmexp, sizeof(uvmexp));
543 1.58 thorpej if (memf != NULL) {
544 1.58 thorpej /*
545 1.58 thorpej * XXX Can't do this if we're reading a crash
546 1.58 thorpej * XXX dump because they're lazily-calculated.
547 1.58 thorpej */
548 1.58 thorpej printf("Unable to get vmtotals from crash dump.\n");
549 1.53 perry memset(&total, 0, sizeof(total));
550 1.58 thorpej } else {
551 1.58 thorpej size = sizeof(total);
552 1.58 thorpej mib[0] = CTL_VM;
553 1.58 thorpej mib[1] = VM_METER;
554 1.58 thorpej if (sysctl(mib, 2, &total, &size, NULL, 0) < 0) {
555 1.58 thorpej printf("Can't get vmtotals: %s\n",
556 1.58 thorpej strerror(errno));
557 1.58 thorpej memset(&total, 0, sizeof(total));
558 1.58 thorpej }
559 1.13 cgd }
560 1.120 dbj (void)printf("%2d %d %d",
561 1.13 cgd total.t_rq - 1, total.t_dw + total.t_pw, total.t_sw);
562 1.75 enami #define pgtok(a) (long)((a) * (pagesize >> 10))
563 1.38 mrg #define rate(x) (u_long)(((x) + halfuptime) / uptime) /* round */
564 1.104 mrg (void)printf(" %6ld %6ld ",
565 1.1 cgd pgtok(total.t_avm), pgtok(total.t_free));
566 1.42 mrg (void)printf("%4lu ", rate(uvmexp.faults - ouvmexp.faults));
567 1.42 mrg (void)printf("%3lu ", rate(uvmexp.pdreact - ouvmexp.pdreact));
568 1.46 mrg (void)printf("%3lu ", rate(uvmexp.pageins - ouvmexp.pageins));
569 1.44 mrg (void)printf("%4lu ",
570 1.44 mrg rate(uvmexp.pgswapout - ouvmexp.pgswapout));
571 1.44 mrg (void)printf("%4lu ", rate(uvmexp.pdfreed - ouvmexp.pdfreed));
572 1.44 mrg (void)printf("%4lu ", rate(uvmexp.pdscans - ouvmexp.pdscans));
573 1.42 mrg dkstats();
574 1.42 mrg (void)printf("%4lu %4lu %3lu ",
575 1.42 mrg rate(uvmexp.intrs - ouvmexp.intrs),
576 1.42 mrg rate(uvmexp.syscalls - ouvmexp.syscalls),
577 1.42 mrg rate(uvmexp.swtch - ouvmexp.swtch));
578 1.42 mrg cpustats();
579 1.87 lukem putchar('\n');
580 1.42 mrg (void)fflush(stdout);
581 1.42 mrg if (reps >= 0 && --reps <= 0)
582 1.42 mrg break;
583 1.42 mrg ouvmexp = uvmexp;
584 1.103 mycroft uptime = interval->tv_sec;
585 1.1 cgd /*
586 1.1 cgd * We round upward to avoid losing low-frequency events
587 1.1 cgd * (i.e., >= 1 per interval but < 1 per second).
588 1.1 cgd */
589 1.33 thorpej halfuptime = uptime == 1 ? 0 : (uptime + 1) / 2;
590 1.103 mycroft nanosleep(interval, NULL);
591 1.1 cgd }
592 1.1 cgd }
593 1.1 cgd
594 1.38 mrg void
595 1.73 simonb printhdr(void)
596 1.1 cgd {
597 1.38 mrg int i;
598 1.1 cgd
599 1.104 mrg (void)printf(" procs memory page%*s", 23, "");
600 1.29 thorpej if (ndrives > 0)
601 1.70 sommerfe (void)printf("%s %*sfaults cpu\n",
602 1.75 enami ((ndrives > 1) ? "disks" : "disk"),
603 1.75 enami ((ndrives > 1) ? ndrives * 3 - 4 : 0), "");
604 1.1 cgd else
605 1.29 thorpej (void)printf("%*s faults cpu\n",
606 1.75 enami ndrives * 3, "");
607 1.29 thorpej
608 1.104 mrg (void)printf(" r b w avm fre flt re pi po fr sr ");
609 1.1 cgd for (i = 0; i < dk_ndrive; i++)
610 1.29 thorpej if (dk_select[i])
611 1.1 cgd (void)printf("%c%c ", dr_name[i][0],
612 1.1 cgd dr_name[i][strlen(dr_name[i]) - 1]);
613 1.1 cgd (void)printf(" in sy cs us sy id\n");
614 1.1 cgd hdrcnt = winlines - 2;
615 1.1 cgd }
616 1.1 cgd
617 1.1 cgd /*
618 1.1 cgd * Force a header to be prepended to the next output.
619 1.1 cgd */
620 1.1 cgd void
621 1.73 simonb needhdr(int dummy)
622 1.1 cgd {
623 1.1 cgd
624 1.1 cgd hdrcnt = 1;
625 1.1 cgd }
626 1.1 cgd
627 1.38 mrg long
628 1.73 simonb pct(long top, long bot)
629 1.1 cgd {
630 1.13 cgd long ans;
631 1.13 cgd
632 1.1 cgd if (bot == 0)
633 1.75 enami return (0);
634 1.13 cgd ans = (quad_t)top * 100 / bot;
635 1.13 cgd return (ans);
636 1.1 cgd }
637 1.1 cgd
638 1.38 mrg #define PCT(top, bot) (int)pct((long)(top), (long)(bot))
639 1.1 cgd
640 1.1 cgd void
641 1.73 simonb dosum(void)
642 1.1 cgd {
643 1.1 cgd struct nchstats nchstats;
644 1.123 enami u_long nchtotal;
645 1.1 cgd
646 1.58 thorpej kread(X_UVMEXP, &uvmexp, sizeof(uvmexp));
647 1.41 mrg
648 1.44 mrg (void)printf("%9u bytes per page\n", uvmexp.pagesize);
649 1.44 mrg
650 1.81 thorpej (void)printf("%9u page color%s\n",
651 1.81 thorpej uvmexp.ncolors, uvmexp.ncolors == 1 ? "" : "s");
652 1.81 thorpej
653 1.44 mrg (void)printf("%9u pages managed\n", uvmexp.npages);
654 1.44 mrg (void)printf("%9u pages free\n", uvmexp.free);
655 1.44 mrg (void)printf("%9u pages active\n", uvmexp.active);
656 1.44 mrg (void)printf("%9u pages inactive\n", uvmexp.inactive);
657 1.44 mrg (void)printf("%9u pages paging\n", uvmexp.paging);
658 1.44 mrg (void)printf("%9u pages wired\n", uvmexp.wired);
659 1.63 thorpej (void)printf("%9u zero pages\n", uvmexp.zeropages);
660 1.44 mrg (void)printf("%9u reserve pagedaemon pages\n",
661 1.44 mrg uvmexp.reserve_pagedaemon);
662 1.44 mrg (void)printf("%9u reserve kernel pages\n", uvmexp.reserve_kernel);
663 1.94 chs (void)printf("%9u anonymous pages\n", uvmexp.anonpages);
664 1.94 chs (void)printf("%9u cached file pages\n", uvmexp.filepages);
665 1.94 chs (void)printf("%9u cached executable pages\n", uvmexp.execpages);
666 1.44 mrg
667 1.44 mrg (void)printf("%9u minimum free pages\n", uvmexp.freemin);
668 1.44 mrg (void)printf("%9u target free pages\n", uvmexp.freetarg);
669 1.44 mrg (void)printf("%9u target inactive pages\n", uvmexp.inactarg);
670 1.44 mrg (void)printf("%9u maximum wired pages\n", uvmexp.wiredmax);
671 1.44 mrg
672 1.44 mrg (void)printf("%9u swap devices\n", uvmexp.nswapdev);
673 1.44 mrg (void)printf("%9u swap pages\n", uvmexp.swpages);
674 1.44 mrg (void)printf("%9u swap pages in use\n", uvmexp.swpginuse);
675 1.44 mrg (void)printf("%9u swap allocations\n", uvmexp.nswget);
676 1.44 mrg (void)printf("%9u anons\n", uvmexp.nanon);
677 1.44 mrg (void)printf("%9u free anons\n", uvmexp.nfreeanon);
678 1.44 mrg
679 1.43 mrg (void)printf("%9u total faults taken\n", uvmexp.faults);
680 1.43 mrg (void)printf("%9u traps\n", uvmexp.traps);
681 1.43 mrg (void)printf("%9u device interrupts\n", uvmexp.intrs);
682 1.121 wiz (void)printf("%9u CPU context switches\n", uvmexp.swtch);
683 1.43 mrg (void)printf("%9u software interrupts\n", uvmexp.softs);
684 1.43 mrg (void)printf("%9u system calls\n", uvmexp.syscalls);
685 1.60 fredb (void)printf("%9u pagein requests\n", uvmexp.pageins);
686 1.60 fredb (void)printf("%9u pageout requests\n", uvmexp.pdpageouts);
687 1.43 mrg (void)printf("%9u swap ins\n", uvmexp.swapins);
688 1.43 mrg (void)printf("%9u swap outs\n", uvmexp.swapouts);
689 1.60 fredb (void)printf("%9u pages swapped in\n", uvmexp.pgswapin);
690 1.60 fredb (void)printf("%9u pages swapped out\n", uvmexp.pgswapout);
691 1.43 mrg (void)printf("%9u forks total\n", uvmexp.forks);
692 1.43 mrg (void)printf("%9u forks blocked parent\n", uvmexp.forks_ppwait);
693 1.43 mrg (void)printf("%9u forks shared address space with parent\n",
694 1.43 mrg uvmexp.forks_sharevm);
695 1.63 thorpej (void)printf("%9u pagealloc zero wanted and avail\n",
696 1.63 thorpej uvmexp.pga_zerohit);
697 1.63 thorpej (void)printf("%9u pagealloc zero wanted and not avail\n",
698 1.63 thorpej uvmexp.pga_zeromiss);
699 1.68 thorpej (void)printf("%9u aborts of idle page zeroing\n",
700 1.68 thorpej uvmexp.zeroaborts);
701 1.79 thorpej (void)printf("%9u pagealloc desired color avail\n",
702 1.79 thorpej uvmexp.colorhit);
703 1.79 thorpej (void)printf("%9u pagealloc desired color not avail\n",
704 1.79 thorpej uvmexp.colormiss);
705 1.44 mrg
706 1.44 mrg (void)printf("%9u faults with no memory\n", uvmexp.fltnoram);
707 1.44 mrg (void)printf("%9u faults with no anons\n", uvmexp.fltnoanon);
708 1.43 mrg (void)printf("%9u faults had to wait on pages\n", uvmexp.fltpgwait);
709 1.43 mrg (void)printf("%9u faults found released page\n", uvmexp.fltpgrele);
710 1.43 mrg (void)printf("%9u faults relock (%u ok)\n", uvmexp.fltrelck,
711 1.43 mrg uvmexp.fltrelckok);
712 1.43 mrg (void)printf("%9u anon page faults\n", uvmexp.fltanget);
713 1.43 mrg (void)printf("%9u anon retry faults\n", uvmexp.fltanretry);
714 1.43 mrg (void)printf("%9u amap copy faults\n", uvmexp.fltamcopy);
715 1.43 mrg (void)printf("%9u neighbour anon page faults\n", uvmexp.fltnamap);
716 1.43 mrg (void)printf("%9u neighbour object page faults\n", uvmexp.fltnomap);
717 1.43 mrg (void)printf("%9u locked pager get faults\n", uvmexp.fltlget);
718 1.43 mrg (void)printf("%9u unlocked pager get faults\n", uvmexp.fltget);
719 1.43 mrg (void)printf("%9u anon faults\n", uvmexp.flt_anon);
720 1.43 mrg (void)printf("%9u anon copy on write faults\n", uvmexp.flt_acow);
721 1.43 mrg (void)printf("%9u object faults\n", uvmexp.flt_obj);
722 1.43 mrg (void)printf("%9u promote copy faults\n", uvmexp.flt_prcopy);
723 1.43 mrg (void)printf("%9u promote zero fill faults\n", uvmexp.flt_przero);
724 1.44 mrg
725 1.44 mrg (void)printf("%9u times daemon wokeup\n",uvmexp.pdwoke);
726 1.44 mrg (void)printf("%9u revolutions of the clock hand\n", uvmexp.pdrevs);
727 1.44 mrg (void)printf("%9u times daemon attempted swapout\n", uvmexp.pdswout);
728 1.44 mrg (void)printf("%9u pages freed by daemon\n", uvmexp.pdfreed);
729 1.44 mrg (void)printf("%9u pages scanned by daemon\n", uvmexp.pdscans);
730 1.75 enami (void)printf("%9u anonymous pages scanned by daemon\n",
731 1.75 enami uvmexp.pdanscan);
732 1.44 mrg (void)printf("%9u object pages scanned by daemon\n", uvmexp.pdobscan);
733 1.44 mrg (void)printf("%9u pages reactivated\n", uvmexp.pdreact);
734 1.123 enami (void)printf("%9u anonymous pages reactivated\n", uvmexp.pdreanon);
735 1.123 enami (void)printf("%9u cached file pages reactivated\n", uvmexp.pdrefile);
736 1.123 enami (void)printf("%9u cached executable pages reactivated\n",
737 1.123 enami uvmexp.pdreexec);
738 1.44 mrg (void)printf("%9u pages found busy by daemon\n", uvmexp.pdbusy);
739 1.44 mrg (void)printf("%9u total pending pageouts\n", uvmexp.pdpending);
740 1.44 mrg (void)printf("%9u pages deactivated\n", uvmexp.pddeact);
741 1.123 enami
742 1.1 cgd kread(X_NCHSTATS, &nchstats, sizeof(nchstats));
743 1.1 cgd nchtotal = nchstats.ncs_goodhits + nchstats.ncs_neghits +
744 1.1 cgd nchstats.ncs_badhits + nchstats.ncs_falsehits +
745 1.1 cgd nchstats.ncs_miss + nchstats.ncs_long;
746 1.123 enami (void)printf("%9lu total name lookups\n", nchtotal);
747 1.123 enami (void)printf("%9lu good hits\n", nchstats.ncs_goodhits);
748 1.123 enami (void)printf("%9lu negative hits\n", nchstats.ncs_neghits);
749 1.123 enami (void)printf("%9lu bad hits\n", nchstats.ncs_badhits);
750 1.123 enami (void)printf("%9lu false hits\n", nchstats.ncs_falsehits);
751 1.123 enami (void)printf("%9lu miss\n", nchstats.ncs_miss);
752 1.123 enami (void)printf("%9lu too long\n", nchstats.ncs_long);
753 1.123 enami (void)printf("%9lu pass2 hits\n", nchstats.ncs_pass2);
754 1.123 enami (void)printf("%9lu 2passes\n", nchstats.ncs_2passes);
755 1.1 cgd (void)printf(
756 1.1 cgd "%9s cache hits (%d%% pos + %d%% neg) system %d%% per-process\n",
757 1.1 cgd "", PCT(nchstats.ncs_goodhits, nchtotal),
758 1.1 cgd PCT(nchstats.ncs_neghits, nchtotal),
759 1.1 cgd PCT(nchstats.ncs_pass2, nchtotal));
760 1.1 cgd (void)printf("%9s deletions %d%%, falsehits %d%%, toolong %d%%\n", "",
761 1.1 cgd PCT(nchstats.ncs_badhits, nchtotal),
762 1.1 cgd PCT(nchstats.ncs_falsehits, nchtotal),
763 1.1 cgd PCT(nchstats.ncs_long, nchtotal));
764 1.1 cgd }
765 1.1 cgd
766 1.1 cgd void
767 1.73 simonb doforkst(void)
768 1.1 cgd {
769 1.41 mrg
770 1.58 thorpej kread(X_UVMEXP, &uvmexp, sizeof(uvmexp));
771 1.58 thorpej
772 1.41 mrg (void)printf("%u forks total\n", uvmexp.forks);
773 1.41 mrg (void)printf("%u forks blocked parent\n", uvmexp.forks_ppwait);
774 1.41 mrg (void)printf("%u forks shared address space with parent\n",
775 1.41 mrg uvmexp.forks_sharevm);
776 1.1 cgd }
777 1.1 cgd
778 1.1 cgd void
779 1.73 simonb dkstats(void)
780 1.1 cgd {
781 1.101 sommerfe int dn;
782 1.1 cgd double etime;
783 1.1 cgd
784 1.29 thorpej /* Calculate disk stat deltas. */
785 1.29 thorpej dkswap();
786 1.101 sommerfe etime = cur.cp_etime;
787 1.101 sommerfe
788 1.1 cgd for (dn = 0; dn < dk_ndrive; ++dn) {
789 1.29 thorpej if (!dk_select[dn])
790 1.1 cgd continue;
791 1.104 mrg (void)printf("%2.0f ",
792 1.104 mrg (cur.dk_rxfer[dn] + cur.dk_wxfer[dn]) / etime);
793 1.1 cgd }
794 1.1 cgd }
795 1.1 cgd
796 1.1 cgd void
797 1.73 simonb cpustats(void)
798 1.1 cgd {
799 1.38 mrg int state;
800 1.1 cgd double pct, total;
801 1.120 dbj double stat_us, stat_sy, stat_id;
802 1.1 cgd
803 1.1 cgd total = 0;
804 1.1 cgd for (state = 0; state < CPUSTATES; ++state)
805 1.29 thorpej total += cur.cp_time[state];
806 1.1 cgd if (total)
807 1.1 cgd pct = 100 / total;
808 1.1 cgd else
809 1.1 cgd pct = 0;
810 1.120 dbj stat_us = (cur.cp_time[CP_USER] + cur.cp_time[CP_NICE]) * pct;
811 1.120 dbj stat_sy = (cur.cp_time[CP_SYS] + cur.cp_time[CP_INTR]) * pct;
812 1.120 dbj stat_id = cur.cp_time[CP_IDLE] * pct;
813 1.120 dbj (void)printf("%*.0f ", ((stat_sy >= 100) ? 1 : 2), stat_us);
814 1.120 dbj (void)printf("%*.0f ", ((stat_us >= 100 || stat_id >= 100) ? 1 : 2), stat_sy);
815 1.120 dbj (void)printf("%2.0f", stat_id);
816 1.1 cgd }
817 1.1 cgd
818 1.1 cgd void
819 1.66 cgd dointr(int verbose)
820 1.1 cgd {
821 1.85 enami unsigned long *intrcnt;
822 1.85 enami unsigned long long inttotal, uptime;
823 1.38 mrg int nintr, inamlen;
824 1.38 mrg char *intrname;
825 1.28 cgd struct evcntlist allevents;
826 1.28 cgd struct evcnt evcnt, *evptr;
827 1.66 cgd char evgroup[EVCNT_STRING_MAX], evname[EVCNT_STRING_MAX];
828 1.1 cgd
829 1.1 cgd uptime = getuptime();
830 1.13 cgd nintr = namelist[X_EINTRCNT].n_value - namelist[X_INTRCNT].n_value;
831 1.13 cgd inamlen =
832 1.13 cgd namelist[X_EINTRNAMES].n_value - namelist[X_INTRNAMES].n_value;
833 1.1 cgd intrcnt = malloc((size_t)nintr);
834 1.1 cgd intrname = malloc((size_t)inamlen);
835 1.87 lukem if (intrcnt == NULL || intrname == NULL)
836 1.87 lukem errx(1, "%s", "");
837 1.1 cgd kread(X_INTRCNT, intrcnt, (size_t)nintr);
838 1.1 cgd kread(X_INTRNAMES, intrname, (size_t)inamlen);
839 1.83 matt (void)printf("%-34s %16s %8s\n", "interrupt", "total", "rate");
840 1.1 cgd inttotal = 0;
841 1.1 cgd nintr /= sizeof(long);
842 1.1 cgd while (--nintr >= 0) {
843 1.66 cgd if (*intrcnt || verbose)
844 1.85 enami (void)printf("%-34s %16llu %8llu\n", intrname,
845 1.85 enami (unsigned long long)*intrcnt,
846 1.85 enami (unsigned long long)(*intrcnt / uptime));
847 1.1 cgd intrname += strlen(intrname) + 1;
848 1.1 cgd inttotal += *intrcnt++;
849 1.1 cgd }
850 1.18 pk kread(X_ALLEVENTS, &allevents, sizeof allevents);
851 1.28 cgd evptr = allevents.tqh_first;
852 1.28 cgd while (evptr) {
853 1.87 lukem deref_kptr(evptr, &evcnt, sizeof(evcnt), "event chain trashed");
854 1.66 cgd evptr = evcnt.ev_list.tqe_next;
855 1.66 cgd if (evcnt.ev_type != EVCNT_TYPE_INTR)
856 1.66 cgd continue;
857 1.66 cgd
858 1.66 cgd if (evcnt.ev_count == 0 && !verbose)
859 1.66 cgd continue;
860 1.66 cgd
861 1.87 lukem deref_kptr(evcnt.ev_group, evgroup, evcnt.ev_grouplen + 1,
862 1.87 lukem "event chain trashed");
863 1.87 lukem deref_kptr(evcnt.ev_name, evname, evcnt.ev_namelen + 1,
864 1.87 lukem "event chain trashed");
865 1.66 cgd
866 1.85 enami (void)printf("%s %s%*s %16llu %8llu\n", evgroup, evname,
867 1.83 matt 34 - (evcnt.ev_grouplen + 1 + evcnt.ev_namelen), "",
868 1.85 enami (unsigned long long)evcnt.ev_count,
869 1.85 enami (unsigned long long)(evcnt.ev_count / uptime));
870 1.66 cgd
871 1.66 cgd inttotal += evcnt.ev_count++;
872 1.66 cgd }
873 1.85 enami (void)printf("%-34s %16llu %8llu\n", "Total", inttotal,
874 1.85 enami (unsigned long long)(inttotal / uptime));
875 1.66 cgd }
876 1.66 cgd
877 1.66 cgd void
878 1.66 cgd doevcnt(int verbose)
879 1.66 cgd {
880 1.83 matt static const char * evtypes [] = { "misc", "intr", "trap" };
881 1.85 enami unsigned long long uptime;
882 1.66 cgd struct evcntlist allevents;
883 1.66 cgd struct evcnt evcnt, *evptr;
884 1.66 cgd char evgroup[EVCNT_STRING_MAX], evname[EVCNT_STRING_MAX];
885 1.66 cgd
886 1.66 cgd /* XXX should print type! */
887 1.66 cgd
888 1.66 cgd uptime = getuptime();
889 1.83 matt (void)printf("%-34s %16s %8s %s\n", "event", "total", "rate", "type");
890 1.66 cgd kread(X_ALLEVENTS, &allevents, sizeof allevents);
891 1.66 cgd evptr = allevents.tqh_first;
892 1.66 cgd while (evptr) {
893 1.87 lukem deref_kptr(evptr, &evcnt, sizeof(evcnt), "event chain trashed");
894 1.32 cgd
895 1.28 cgd evptr = evcnt.ev_list.tqe_next;
896 1.66 cgd if (evcnt.ev_count == 0 && !verbose)
897 1.66 cgd continue;
898 1.66 cgd
899 1.87 lukem deref_kptr(evcnt.ev_group, evgroup, evcnt.ev_grouplen + 1,
900 1.87 lukem "event chain trashed");
901 1.87 lukem deref_kptr(evcnt.ev_name, evname, evcnt.ev_namelen + 1,
902 1.87 lukem "event chain trashed");
903 1.66 cgd
904 1.85 enami (void)printf("%s %s%*s %16llu %8llu %s\n", evgroup, evname,
905 1.83 matt 34 - (evcnt.ev_grouplen + 1 + evcnt.ev_namelen), "",
906 1.85 enami (unsigned long long)evcnt.ev_count,
907 1.85 enami (unsigned long long)(evcnt.ev_count / uptime),
908 1.86 enami (evcnt.ev_type < sizeof(evtypes)/sizeof(evtypes[0]) ?
909 1.86 enami evtypes[evcnt.ev_type] : "?"));
910 1.18 pk }
911 1.1 cgd }
912 1.1 cgd
913 1.109 thorpej static char memname[64];
914 1.1 cgd
915 1.1 cgd void
916 1.73 simonb domem(void)
917 1.1 cgd {
918 1.38 mrg struct kmembuckets *kp;
919 1.109 thorpej struct malloc_type ks, *ksp;
920 1.38 mrg int i, j;
921 1.13 cgd int len, size, first;
922 1.13 cgd long totuse = 0, totfree = 0, totreq = 0;
923 1.1 cgd struct kmembuckets buckets[MINBUCKET + 16];
924 1.1 cgd
925 1.1 cgd kread(X_KMEMBUCKETS, buckets, sizeof(buckets));
926 1.34 thorpej for (first = 1, i = MINBUCKET, kp = &buckets[i]; i < MINBUCKET + 16;
927 1.34 thorpej i++, kp++) {
928 1.1 cgd if (kp->kb_calls == 0)
929 1.1 cgd continue;
930 1.34 thorpej if (first) {
931 1.34 thorpej (void)printf("Memory statistics by bucket size\n");
932 1.34 thorpej (void)printf(
933 1.34 thorpej " Size In Use Free Requests HighWater Couldfree\n");
934 1.34 thorpej first = 0;
935 1.34 thorpej }
936 1.1 cgd size = 1 << i;
937 1.75 enami (void)printf("%8d %8ld %6ld %10ld %7ld %10ld\n", size,
938 1.75 enami kp->kb_total - kp->kb_totalfree,
939 1.75 enami kp->kb_totalfree, kp->kb_calls,
940 1.75 enami kp->kb_highwat, kp->kb_couldfree);
941 1.1 cgd totfree += size * kp->kb_totalfree;
942 1.34 thorpej }
943 1.34 thorpej
944 1.34 thorpej /*
945 1.34 thorpej * If kmem statistics are not being gathered by the kernel,
946 1.34 thorpej * first will still be 1.
947 1.34 thorpej */
948 1.34 thorpej if (first) {
949 1.87 lukem warnx("Kmem statistics are not being gathered by the kernel.");
950 1.34 thorpej return;
951 1.1 cgd }
952 1.1 cgd
953 1.13 cgd (void)printf("\nMemory usage type by bucket size\n");
954 1.13 cgd (void)printf(" Size Type(s)\n");
955 1.13 cgd kp = &buckets[MINBUCKET];
956 1.13 cgd for (j = 1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1, kp++) {
957 1.13 cgd if (kp->kb_calls == 0)
958 1.13 cgd continue;
959 1.13 cgd first = 1;
960 1.13 cgd len = 8;
961 1.109 thorpej for (kread(X_KMEMSTAT, &ksp, sizeof(ksp));
962 1.109 thorpej ksp != NULL; ksp = ks.ks_next) {
963 1.109 thorpej deref_kptr(ksp, &ks, sizeof(ks), "malloc type");
964 1.109 thorpej if (ks.ks_calls == 0)
965 1.13 cgd continue;
966 1.109 thorpej if ((ks.ks_size & j) == 0)
967 1.13 cgd continue;
968 1.109 thorpej deref_kptr(ks.ks_shortdesc, memname,
969 1.109 thorpej sizeof(memname), "malloc type name");
970 1.109 thorpej len += 2 + strlen(memname);
971 1.13 cgd if (first)
972 1.109 thorpej printf("%8d %s", j, memname);
973 1.13 cgd else
974 1.13 cgd printf(",");
975 1.13 cgd if (len >= 80) {
976 1.13 cgd printf("\n\t ");
977 1.109 thorpej len = 10 + strlen(memname);
978 1.13 cgd }
979 1.13 cgd if (!first)
980 1.109 thorpej printf(" %s", memname);
981 1.13 cgd first = 0;
982 1.13 cgd }
983 1.87 lukem putchar('\n');
984 1.13 cgd }
985 1.13 cgd
986 1.1 cgd (void)printf(
987 1.119 simonb "\nMemory statistics by type Type Kern\n");
988 1.13 cgd (void)printf(
989 1.36 is " Type InUse MemUse HighUse Limit Requests Limit Limit Size(s)\n");
990 1.109 thorpej for (kread(X_KMEMSTAT, &ksp, sizeof(ksp));
991 1.109 thorpej ksp != NULL; ksp = ks.ks_next) {
992 1.109 thorpej deref_kptr(ksp, &ks, sizeof(ks), "malloc type");
993 1.109 thorpej if (ks.ks_calls == 0)
994 1.1 cgd continue;
995 1.109 thorpej deref_kptr(ks.ks_shortdesc, memname,
996 1.109 thorpej sizeof(memname), "malloc type name");
997 1.36 is (void)printf("%14s%6ld%6ldK%7ldK%6ldK%9ld%5u%6u",
998 1.109 thorpej memname,
999 1.109 thorpej ks.ks_inuse, (ks.ks_memuse + 1023) / 1024,
1000 1.109 thorpej (ks.ks_maxused + 1023) / 1024,
1001 1.109 thorpej (ks.ks_limit + 1023) / 1024, ks.ks_calls,
1002 1.109 thorpej ks.ks_limblocks, ks.ks_mapblocks);
1003 1.13 cgd first = 1;
1004 1.13 cgd for (j = 1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1) {
1005 1.109 thorpej if ((ks.ks_size & j) == 0)
1006 1.13 cgd continue;
1007 1.13 cgd if (first)
1008 1.13 cgd printf(" %d", j);
1009 1.13 cgd else
1010 1.13 cgd printf(",%d", j);
1011 1.13 cgd first = 0;
1012 1.13 cgd }
1013 1.13 cgd printf("\n");
1014 1.109 thorpej totuse += ks.ks_memuse;
1015 1.109 thorpej totreq += ks.ks_calls;
1016 1.1 cgd }
1017 1.102 soren (void)printf("\nMemory totals: In Use Free Requests\n");
1018 1.102 soren (void)printf(" %7ldK %6ldK %8ld\n\n",
1019 1.75 enami (totuse + 1023) / 1024, (totfree + 1023) / 1024, totreq);
1020 1.51 pk }
1021 1.51 pk
1022 1.51 pk void
1023 1.96 enami dopool(int verbose)
1024 1.51 pk {
1025 1.69 enami int first, ovflw;
1026 1.87 lukem void *addr;
1027 1.51 pk long total = 0, inuse = 0;
1028 1.51 pk TAILQ_HEAD(,pool) pool_head;
1029 1.51 pk struct pool pool, *pp = &pool;
1030 1.98 christos struct pool_allocator pa;
1031 1.87 lukem char name[32], maxp[32];
1032 1.51 pk
1033 1.51 pk kread(X_POOLHEAD, &pool_head, sizeof(pool_head));
1034 1.87 lukem addr = TAILQ_FIRST(&pool_head);
1035 1.51 pk
1036 1.113 dsl for (first = 1; addr != NULL; addr = TAILQ_NEXT(pp, pr_poollist) ) {
1037 1.87 lukem deref_kptr(addr, pp, sizeof(*pp), "pool chain trashed");
1038 1.98 christos deref_kptr(pp->pr_alloc, &pa, sizeof(pa),
1039 1.125 dsainty "pool allocator trashed");
1040 1.87 lukem deref_kptr(pp->pr_wchan, name, sizeof(name),
1041 1.98 christos "pool wait channel trashed");
1042 1.87 lukem name[sizeof(name)-1] = '\0';
1043 1.51 pk
1044 1.51 pk if (first) {
1045 1.51 pk (void)printf("Memory resource pool statistics\n");
1046 1.51 pk (void)printf(
1047 1.75 enami "%-11s%5s%9s%5s%9s%6s%6s%6s%6s%6s%6s%5s\n",
1048 1.75 enami "Name",
1049 1.75 enami "Size",
1050 1.75 enami "Requests",
1051 1.75 enami "Fail",
1052 1.75 enami "Releases",
1053 1.75 enami "Pgreq",
1054 1.75 enami "Pgrel",
1055 1.75 enami "Npage",
1056 1.75 enami "Hiwat",
1057 1.75 enami "Minpg",
1058 1.75 enami "Maxpg",
1059 1.75 enami "Idle");
1060 1.51 pk first = 0;
1061 1.51 pk }
1062 1.113 dsl if (pp->pr_nget == 0 && !verbose)
1063 1.113 dsl continue;
1064 1.51 pk if (pp->pr_maxpages == UINT_MAX)
1065 1.116 itojun snprintf(maxp, sizeof(maxp), "inf");
1066 1.51 pk else
1067 1.116 itojun snprintf(maxp, sizeof(maxp), "%u", pp->pr_maxpages);
1068 1.69 enami /*
1069 1.69 enami * Print single word. `ovflow' is number of characters didn't fit
1070 1.69 enami * on the last word. `fmt' is a format string to print this word.
1071 1.69 enami * It must contain asterisk for field width. `width' is a width
1072 1.69 enami * occupied by this word. `fixed' is a number of constant chars in
1073 1.69 enami * `fmt'. `val' is a value to be printed using format string `fmt'.
1074 1.69 enami */
1075 1.69 enami #define PRWORD(ovflw, fmt, width, fixed, val) do { \
1076 1.69 enami (ovflw) += printf((fmt), \
1077 1.69 enami (width) - (fixed) - (ovflw) > 0 ? \
1078 1.69 enami (width) - (fixed) - (ovflw) : 0, \
1079 1.69 enami (val)) - (width); \
1080 1.69 enami if ((ovflw) < 0) \
1081 1.69 enami (ovflw) = 0; \
1082 1.69 enami } while (/* CONSTCOND */0)
1083 1.69 enami ovflw = 0;
1084 1.69 enami PRWORD(ovflw, "%-*s", 11, 0, name);
1085 1.69 enami PRWORD(ovflw, " %*u", 5, 1, pp->pr_size);
1086 1.69 enami PRWORD(ovflw, " %*lu", 9, 1, pp->pr_nget);
1087 1.69 enami PRWORD(ovflw, " %*lu", 5, 1, pp->pr_nfail);
1088 1.69 enami PRWORD(ovflw, " %*lu", 9, 1, pp->pr_nput);
1089 1.69 enami PRWORD(ovflw, " %*lu", 6, 1, pp->pr_npagealloc);
1090 1.69 enami PRWORD(ovflw, " %*lu", 6, 1, pp->pr_npagefree);
1091 1.69 enami PRWORD(ovflw, " %*d", 6, 1, pp->pr_npages);
1092 1.69 enami PRWORD(ovflw, " %*d", 6, 1, pp->pr_hiwat);
1093 1.69 enami PRWORD(ovflw, " %*d", 6, 1, pp->pr_minpages);
1094 1.69 enami PRWORD(ovflw, " %*s", 6, 1, maxp);
1095 1.69 enami PRWORD(ovflw, " %*lu\n", 5, 1, pp->pr_nidle);
1096 1.51 pk
1097 1.84 bjh21 if (pp->pr_roflags & PR_RECURSIVE) {
1098 1.84 bjh21 /*
1099 1.84 bjh21 * Don't count in-use memory, since it's part
1100 1.84 bjh21 * of another pool and will be accounted for
1101 1.84 bjh21 * there.
1102 1.84 bjh21 */
1103 1.98 christos total += pp->pr_npages * pa.pa_pagesz -
1104 1.84 bjh21 (pp->pr_nget - pp->pr_nput) * pp->pr_size;
1105 1.84 bjh21 } else {
1106 1.84 bjh21 inuse += (pp->pr_nget - pp->pr_nput) * pp->pr_size;
1107 1.98 christos total += pp->pr_npages * pa.pa_pagesz;
1108 1.84 bjh21 }
1109 1.96 enami dopoolcache(pp, verbose);
1110 1.51 pk }
1111 1.51 pk
1112 1.76 enami inuse /= 1024;
1113 1.76 enami total /= 1024;
1114 1.51 pk printf("\nIn use %ldK, total allocated %ldK; utilization %.1f%%\n",
1115 1.76 enami inuse, total, (double)(100 * inuse) / total);
1116 1.1 cgd }
1117 1.96 enami
1118 1.96 enami void
1119 1.96 enami dopoolcache(struct pool *pp, int verbose)
1120 1.96 enami {
1121 1.96 enami struct pool_cache pool_cache, *pc = &pool_cache;
1122 1.96 enami struct pool_cache_group pool_cache_group, *pcg = &pool_cache_group;
1123 1.96 enami void *addr, *pcg_addr;
1124 1.96 enami int i;
1125 1.96 enami
1126 1.96 enami if (verbose < 1)
1127 1.96 enami return;
1128 1.96 enami
1129 1.96 enami for (addr = TAILQ_FIRST(&pp->pr_cachelist); addr != NULL;
1130 1.96 enami addr = TAILQ_NEXT(pc, pc_poollist)) {
1131 1.96 enami deref_kptr(addr, pc, sizeof(*pc), "pool cache trashed");
1132 1.96 enami printf("\tcache %p: allocfrom %p freeto %p\n", addr,
1133 1.96 enami pc->pc_allocfrom, pc->pc_freeto);
1134 1.96 enami printf("\t hits %lu misses %lu ngroups %lu nitems %lu\n",
1135 1.96 enami pc->pc_hits, pc->pc_misses, pc->pc_ngroups, pc->pc_nitems);
1136 1.96 enami if (verbose < 2)
1137 1.96 enami continue;
1138 1.96 enami for (pcg_addr = TAILQ_FIRST(&pc->pc_grouplist);
1139 1.96 enami pcg_addr != NULL; pcg_addr = TAILQ_NEXT(pcg, pcg_list)) {
1140 1.97 enami deref_kptr(pcg_addr, pcg, sizeof(*pcg),
1141 1.97 enami "pool cache group trashed");
1142 1.96 enami printf("\t\tgroup %p: avail %d\n", pcg_addr,
1143 1.96 enami pcg->pcg_avail);
1144 1.112 thorpej for (i = 0; i < PCG_NOBJECTS; i++) {
1145 1.112 thorpej if (pcg->pcg_objects[i].pcgo_pa !=
1146 1.112 thorpej POOL_PADDR_INVALID) {
1147 1.112 thorpej printf("\t\t\t%p, 0x%llx\n",
1148 1.112 thorpej pcg->pcg_objects[i].pcgo_va,
1149 1.112 thorpej (unsigned long long)
1150 1.112 thorpej pcg->pcg_objects[i].pcgo_pa);
1151 1.112 thorpej } else {
1152 1.112 thorpej printf("\t\t\t%p\n",
1153 1.112 thorpej pcg->pcg_objects[i].pcgo_va);
1154 1.112 thorpej }
1155 1.112 thorpej }
1156 1.96 enami }
1157 1.96 enami }
1158 1.96 enami
1159 1.96 enami }
1160 1.90 lukem
1161 1.87 lukem enum hashtype { /* from <sys/systm.h> */
1162 1.87 lukem HASH_LIST,
1163 1.87 lukem HASH_TAILQ
1164 1.87 lukem };
1165 1.87 lukem
1166 1.87 lukem struct uidinfo { /* XXX: no kernel header file */
1167 1.87 lukem LIST_ENTRY(uidinfo) ui_hash;
1168 1.87 lukem uid_t ui_uid;
1169 1.87 lukem long ui_proccnt;
1170 1.87 lukem };
1171 1.87 lukem
1172 1.87 lukem struct kernel_hash {
1173 1.90 lukem const char * description; /* description */
1174 1.90 lukem int hashsize; /* nlist index for hash size */
1175 1.90 lukem int hashtbl; /* nlist index for hash table */
1176 1.90 lukem enum hashtype type; /* type of hash table */
1177 1.101 sommerfe size_t offset; /* offset of {LIST,TAILQ}_NEXT */
1178 1.87 lukem } khashes[] =
1179 1.87 lukem {
1180 1.87 lukem {
1181 1.90 lukem "buffer hash",
1182 1.90 lukem X_BUFHASH, X_BUFHASHTBL,
1183 1.90 lukem HASH_LIST, offsetof(struct buf, b_hash)
1184 1.90 lukem }, {
1185 1.90 lukem "inode cache (ihash)",
1186 1.87 lukem X_IHASH, X_IHASHTBL,
1187 1.87 lukem HASH_LIST, offsetof(struct inode, i_hash)
1188 1.90 lukem }, {
1189 1.90 lukem "ipv4 address -> interface hash",
1190 1.87 lukem X_IFADDRHASH, X_IFADDRHASHTBL,
1191 1.87 lukem HASH_LIST, offsetof(struct in_ifaddr, ia_hash),
1192 1.90 lukem }, {
1193 1.90 lukem "name cache hash",
1194 1.89 lukem X_NCHASH, X_NCHASHTBL,
1195 1.89 lukem HASH_LIST, offsetof(struct namecache, nc_hash),
1196 1.90 lukem }, {
1197 1.90 lukem "name cache directory hash",
1198 1.89 lukem X_NCVHASH, X_NCVHASHTBL,
1199 1.89 lukem HASH_LIST, offsetof(struct namecache, nc_vhash),
1200 1.90 lukem }, {
1201 1.90 lukem "nfs client node cache",
1202 1.90 lukem X_NFSNODE, X_NFSNODETBL,
1203 1.90 lukem HASH_LIST, offsetof(struct nfsnode, n_hash)
1204 1.90 lukem }, {
1205 1.90 lukem "user info (uid -> used processes) hash",
1206 1.90 lukem X_UIHASH, X_UIHASHTBL,
1207 1.90 lukem HASH_LIST, offsetof(struct uidinfo, ui_hash),
1208 1.90 lukem }, {
1209 1.90 lukem NULL, -1, -1, 0, 0,
1210 1.87 lukem }
1211 1.87 lukem };
1212 1.87 lukem
1213 1.87 lukem void
1214 1.88 lukem dohashstat(int verbose, int todo, const char *hashname)
1215 1.101 sommerfe {
1216 1.87 lukem LIST_HEAD(, generic) *hashtbl_list;
1217 1.87 lukem TAILQ_HEAD(, generic) *hashtbl_tailq;
1218 1.87 lukem struct kernel_hash *curhash;
1219 1.118 itojun void *hashaddr, *hashbuf, *nhashbuf, *nextaddr;
1220 1.87 lukem size_t elemsize, hashbufsize, thissize;
1221 1.87 lukem u_long hashsize;
1222 1.87 lukem int i, used, items, chain, maxchain;
1223 1.87 lukem
1224 1.87 lukem hashbuf = NULL;
1225 1.87 lukem hashbufsize = 0;
1226 1.88 lukem
1227 1.88 lukem if (todo & HASHLIST) {
1228 1.90 lukem printf("Supported hashes:\n");
1229 1.90 lukem for (curhash = khashes; curhash->description; curhash++) {
1230 1.101 sommerfe if (hashnl[curhash->hashsize].n_value == 0 ||
1231 1.90 lukem hashnl[curhash->hashtbl].n_value == 0)
1232 1.90 lukem continue;
1233 1.90 lukem printf("\t%-16s%s\n",
1234 1.90 lukem hashnl[curhash->hashsize].n_name + 1,
1235 1.90 lukem curhash->description);
1236 1.88 lukem }
1237 1.88 lukem return;
1238 1.88 lukem }
1239 1.88 lukem
1240 1.88 lukem if (hashname != NULL) {
1241 1.90 lukem for (curhash = khashes; curhash->description; curhash++) {
1242 1.90 lukem if (strcmp(hashnl[curhash->hashsize].n_name + 1,
1243 1.90 lukem hashname) == 0 &&
1244 1.101 sommerfe hashnl[curhash->hashsize].n_value != 0 &&
1245 1.90 lukem hashnl[curhash->hashtbl].n_value != 0)
1246 1.88 lukem break;
1247 1.88 lukem }
1248 1.90 lukem if (curhash->description == NULL) {
1249 1.90 lukem warnx("%s: no such hash", hashname);
1250 1.90 lukem return;
1251 1.90 lukem }
1252 1.88 lukem }
1253 1.88 lukem
1254 1.88 lukem printf(
1255 1.88 lukem "%-16s %8s %8s %8s %8s %8s %8s\n"
1256 1.88 lukem "%-16s %8s %8s %8s %8s %8s %8s\n",
1257 1.88 lukem "", "total", "used", "util", "num", "average", "maximum",
1258 1.88 lukem "hash table", "buckets", "buckets", "%", "items", "chain",
1259 1.88 lukem "chain");
1260 1.87 lukem
1261 1.90 lukem for (curhash = khashes; curhash->description; curhash++) {
1262 1.101 sommerfe if (hashnl[curhash->hashsize].n_value == 0 ||
1263 1.90 lukem hashnl[curhash->hashtbl].n_value == 0)
1264 1.90 lukem continue;
1265 1.88 lukem if (hashname != NULL &&
1266 1.90 lukem strcmp(hashnl[curhash->hashsize].n_name + 1, hashname))
1267 1.88 lukem continue;
1268 1.87 lukem elemsize = curhash->type == HASH_LIST ?
1269 1.87 lukem sizeof(*hashtbl_list) : sizeof(*hashtbl_tailq);
1270 1.90 lukem deref_kptr((void *)hashnl[curhash->hashsize].n_value,
1271 1.90 lukem &hashsize, sizeof(hashsize),
1272 1.90 lukem hashnl[curhash->hashsize].n_name);
1273 1.87 lukem hashsize++;
1274 1.90 lukem deref_kptr((void *)hashnl[curhash->hashtbl].n_value,
1275 1.90 lukem &hashaddr, sizeof(hashaddr),
1276 1.90 lukem hashnl[curhash->hashtbl].n_name);
1277 1.87 lukem if (verbose)
1278 1.91 jmc printf("%s %lu, %s %p, offset %ld, elemsize %llu\n",
1279 1.90 lukem hashnl[curhash->hashsize].n_name + 1, hashsize,
1280 1.90 lukem hashnl[curhash->hashtbl].n_name + 1, hashaddr,
1281 1.101 sommerfe (long)curhash->offset,
1282 1.91 jmc (unsigned long long)elemsize);
1283 1.87 lukem thissize = hashsize * elemsize;
1284 1.87 lukem if (thissize > hashbufsize) {
1285 1.118 itojun if ((nhashbuf = realloc(hashbuf, thissize)) == NULL)
1286 1.101 sommerfe errx(1, "malloc hashbuf %llu",
1287 1.91 jmc (unsigned long long)hashbufsize);
1288 1.118 itojun hashbuf = nhashbuf;
1289 1.118 itojun hashbufsize = thissize;
1290 1.87 lukem }
1291 1.87 lukem deref_kptr(hashaddr, hashbuf, thissize,
1292 1.90 lukem hashnl[curhash->hashtbl].n_name);
1293 1.87 lukem used = 0;
1294 1.87 lukem items = maxchain = 0;
1295 1.87 lukem if (curhash->type == HASH_LIST)
1296 1.87 lukem hashtbl_list = hashbuf;
1297 1.87 lukem else
1298 1.87 lukem hashtbl_tailq = hashbuf;
1299 1.87 lukem for (i = 0; i < hashsize; i++) {
1300 1.87 lukem if (curhash->type == HASH_LIST)
1301 1.87 lukem nextaddr = LIST_FIRST(&hashtbl_list[i]);
1302 1.87 lukem else
1303 1.87 lukem nextaddr = TAILQ_FIRST(&hashtbl_tailq[i]);
1304 1.87 lukem if (nextaddr == NULL)
1305 1.87 lukem continue;
1306 1.87 lukem if (verbose)
1307 1.87 lukem printf("%5d: %p\n", i, nextaddr);
1308 1.87 lukem used++;
1309 1.87 lukem chain = 0;
1310 1.87 lukem do {
1311 1.87 lukem chain++;
1312 1.87 lukem deref_kptr((char *)nextaddr + curhash->offset,
1313 1.87 lukem &nextaddr, sizeof(void *),
1314 1.87 lukem "hash chain corrupted");
1315 1.87 lukem if (verbose > 1)
1316 1.87 lukem printf("got nextaddr as %p\n",
1317 1.87 lukem nextaddr);
1318 1.87 lukem } while (nextaddr != NULL);
1319 1.87 lukem items += chain;
1320 1.87 lukem if (verbose && chain > 1)
1321 1.87 lukem printf("\tchain = %d\n", chain);
1322 1.87 lukem if (chain > maxchain)
1323 1.87 lukem maxchain = chain;
1324 1.87 lukem }
1325 1.93 lukem printf("%-16s %8ld %8d %8.2f %8d %8.2f %8d\n",
1326 1.90 lukem hashnl[curhash->hashsize].n_name + 1,
1327 1.87 lukem hashsize, used, used * 100.0 / hashsize,
1328 1.93 lukem items, used ? (double)items / used : 0.0, maxchain);
1329 1.87 lukem }
1330 1.87 lukem }
1331 1.87 lukem
1332 1.1 cgd /*
1333 1.90 lukem * kread reads something from the kernel, given its nlist index in namelist[].
1334 1.1 cgd */
1335 1.1 cgd void
1336 1.73 simonb kread(int nlx, void *addr, size_t size)
1337 1.1 cgd {
1338 1.50 mycroft const char *sym;
1339 1.1 cgd
1340 1.87 lukem sym = namelist[nlx].n_name;
1341 1.87 lukem if (*sym == '_')
1342 1.87 lukem ++sym;
1343 1.87 lukem if (namelist[nlx].n_type == 0 || namelist[nlx].n_value == 0)
1344 1.87 lukem errx(1, "symbol %s not defined", sym);
1345 1.87 lukem deref_kptr((void *)namelist[nlx].n_value, addr, size, sym);
1346 1.87 lukem }
1347 1.87 lukem
1348 1.87 lukem /*
1349 1.101 sommerfe * Dereference the kernel pointer `kptr' and fill in the local copy
1350 1.87 lukem * pointed to by `ptr'. The storage space must be pre-allocated,
1351 1.87 lukem * and the size of the copy passed in `len'.
1352 1.87 lukem */
1353 1.87 lukem void
1354 1.87 lukem deref_kptr(const void *kptr, void *ptr, size_t len, const char *msg)
1355 1.87 lukem {
1356 1.87 lukem
1357 1.87 lukem if (*msg == '_')
1358 1.87 lukem msg++;
1359 1.87 lukem if (kvm_read(kd, (u_long)kptr, (char *)ptr, len) != len)
1360 1.87 lukem errx(1, "kptr %lx: %s: %s", (u_long)kptr, msg, kvm_geterr(kd));
1361 1.1 cgd }
1362 1.1 cgd
1363 1.45 thorpej /*
1364 1.45 thorpej * Traverse the UVM history buffers, performing the requested action.
1365 1.45 thorpej *
1366 1.45 thorpej * Note, we assume that if we're not listing, we're dumping.
1367 1.45 thorpej */
1368 1.45 thorpej void
1369 1.73 simonb hist_traverse(int todo, const char *histname)
1370 1.45 thorpej {
1371 1.45 thorpej struct uvm_history_head histhead;
1372 1.45 thorpej struct uvm_history hist, *histkva;
1373 1.45 thorpej char *name = NULL;
1374 1.45 thorpej size_t namelen = 0;
1375 1.45 thorpej
1376 1.90 lukem if (histnl[0].n_value == 0) {
1377 1.87 lukem warnx("UVM history is not compiled into the kernel.");
1378 1.45 thorpej return;
1379 1.45 thorpej }
1380 1.45 thorpej
1381 1.87 lukem deref_kptr((void *)histnl[X_UVM_HISTORIES].n_value, &histhead,
1382 1.87 lukem sizeof(histhead), histnl[X_UVM_HISTORIES].n_name);
1383 1.45 thorpej
1384 1.45 thorpej if (histhead.lh_first == NULL) {
1385 1.87 lukem warnx("No active UVM history logs.");
1386 1.45 thorpej return;
1387 1.45 thorpej }
1388 1.45 thorpej
1389 1.45 thorpej if (todo & HISTLIST)
1390 1.45 thorpej printf("Active UVM histories:");
1391 1.45 thorpej
1392 1.75 enami for (histkva = LIST_FIRST(&histhead); histkva != NULL;
1393 1.75 enami histkva = LIST_NEXT(&hist, list)) {
1394 1.87 lukem deref_kptr(histkva, &hist, sizeof(hist), "histkva");
1395 1.45 thorpej if (hist.namelen > namelen) {
1396 1.45 thorpej if (name != NULL)
1397 1.45 thorpej free(name);
1398 1.45 thorpej namelen = hist.namelen;
1399 1.45 thorpej if ((name = malloc(namelen + 1)) == NULL)
1400 1.45 thorpej err(1, "malloc history name");
1401 1.45 thorpej }
1402 1.45 thorpej
1403 1.87 lukem deref_kptr(hist.name, name, namelen, "history name");
1404 1.45 thorpej name[namelen] = '\0';
1405 1.45 thorpej if (todo & HISTLIST)
1406 1.45 thorpej printf(" %s", name);
1407 1.45 thorpej else {
1408 1.45 thorpej /*
1409 1.45 thorpej * If we're dumping all histories, do it, else
1410 1.45 thorpej * check to see if this is the one we want.
1411 1.45 thorpej */
1412 1.45 thorpej if (histname == NULL || strcmp(histname, name) == 0) {
1413 1.45 thorpej if (histname == NULL)
1414 1.45 thorpej printf("\nUVM history `%s':\n", name);
1415 1.45 thorpej hist_dodump(&hist);
1416 1.45 thorpej }
1417 1.45 thorpej }
1418 1.45 thorpej }
1419 1.45 thorpej
1420 1.45 thorpej if (todo & HISTLIST)
1421 1.87 lukem putchar('\n');
1422 1.45 thorpej
1423 1.45 thorpej if (name != NULL)
1424 1.45 thorpej free(name);
1425 1.45 thorpej }
1426 1.45 thorpej
1427 1.45 thorpej /*
1428 1.45 thorpej * Actually dump the history buffer at the specified KVA.
1429 1.45 thorpej */
1430 1.45 thorpej void
1431 1.73 simonb hist_dodump(struct uvm_history *histp)
1432 1.45 thorpej {
1433 1.45 thorpej struct uvm_history_ent *histents, *e;
1434 1.45 thorpej size_t histsize;
1435 1.45 thorpej char *fmt = NULL, *fn = NULL;
1436 1.45 thorpej size_t fmtlen = 0, fnlen = 0;
1437 1.45 thorpej int i;
1438 1.45 thorpej
1439 1.45 thorpej histsize = sizeof(struct uvm_history_ent) * histp->n;
1440 1.45 thorpej
1441 1.45 thorpej if ((histents = malloc(histsize)) == NULL)
1442 1.45 thorpej err(1, "malloc history entries");
1443 1.45 thorpej
1444 1.45 thorpej memset(histents, 0, histsize);
1445 1.45 thorpej
1446 1.87 lukem deref_kptr(histp->e, histents, histsize, "history entries");
1447 1.45 thorpej i = histp->f;
1448 1.45 thorpej do {
1449 1.45 thorpej e = &histents[i];
1450 1.45 thorpej if (e->fmt != NULL) {
1451 1.45 thorpej if (e->fmtlen > fmtlen) {
1452 1.45 thorpej if (fmt != NULL)
1453 1.45 thorpej free(fmt);
1454 1.45 thorpej fmtlen = e->fmtlen;
1455 1.45 thorpej if ((fmt = malloc(fmtlen + 1)) == NULL)
1456 1.45 thorpej err(1, "malloc printf format");
1457 1.45 thorpej }
1458 1.45 thorpej if (e->fnlen > fnlen) {
1459 1.45 thorpej if (fn != NULL)
1460 1.45 thorpej free(fn);
1461 1.45 thorpej fnlen = e->fnlen;
1462 1.45 thorpej if ((fn = malloc(fnlen + 1)) == NULL)
1463 1.45 thorpej err(1, "malloc function name");
1464 1.45 thorpej }
1465 1.45 thorpej
1466 1.87 lukem deref_kptr(e->fmt, fmt, fmtlen, "printf format");
1467 1.45 thorpej fmt[fmtlen] = '\0';
1468 1.45 thorpej
1469 1.87 lukem deref_kptr(e->fn, fn, fnlen, "function name");
1470 1.45 thorpej fn[fnlen] = '\0';
1471 1.45 thorpej
1472 1.61 kleink printf("%06ld.%06ld ", (long int)e->tv.tv_sec,
1473 1.61 kleink (long int)e->tv.tv_usec);
1474 1.75 enami printf("%s#%ld: ", fn, e->call);
1475 1.45 thorpej printf(fmt, e->v[0], e->v[1], e->v[2], e->v[3]);
1476 1.87 lukem putchar('\n');
1477 1.45 thorpej }
1478 1.45 thorpej i = (i + 1) % histp->n;
1479 1.45 thorpej } while (i != histp->f);
1480 1.45 thorpej
1481 1.45 thorpej free(histents);
1482 1.45 thorpej if (fmt != NULL)
1483 1.45 thorpej free(fmt);
1484 1.45 thorpej if (fn != NULL)
1485 1.45 thorpej free(fn);
1486 1.45 thorpej }
1487 1.45 thorpej
1488 1.1 cgd void
1489 1.73 simonb usage(void)
1490 1.1 cgd {
1491 1.47 mrg
1492 1.1 cgd (void)fprintf(stderr,
1493 1.88 lukem "usage: %s [-efHilmsUv] [-h hashname] [-u histname] [-c count]\n"
1494 1.88 lukem "\t\t[-M core] [-N system] [-w wait] [disks]\n", getprogname());
1495 1.1 cgd exit(1);
1496 1.1 cgd }
1497