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