K&R style function removal. Update functions to ANSI style.
[dragonfly.git] / usr.bin / vmstat / vmstat.c
1 /*
2  * Copyright (c) 1980, 1986, 1991, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * @(#) Copyright (c) 1980, 1986, 1991, 1993 The Regents of the University of California.  All rights reserved.
34  * @(#)vmstat.c 8.1 (Berkeley) 6/6/93
35  * $FreeBSD: src/usr.bin/vmstat/vmstat.c,v 1.38.2.4 2001/07/31 19:52:41 tmm Exp $
36  * $DragonFly: src/usr.bin/vmstat/vmstat.c,v 1.7 2003/10/04 20:36:54 hmp Exp $
37  */
38
39 #define _KERNEL_STRUCTURES
40 #include <sys/param.h>
41 #include <sys/time.h>
42 #include <sys/proc.h>
43 #include <sys/dkstat.h>
44 #include <sys/uio.h>
45 #include <sys/namei.h>
46 #include <sys/malloc.h>
47 #include <sys/signal.h>
48 #include <sys/fcntl.h>
49 #include <sys/ioctl.h>
50 #include <sys/sysctl.h>
51 #include <sys/vmmeter.h>
52
53 #include <vm/vm_param.h>
54
55 #include <ctype.h>
56 #include <err.h>
57 #include <errno.h>
58 #include <kvm.h>
59 #include <limits.h>
60 #include <nlist.h>
61 #include <paths.h>
62 #include <stdio.h>
63 #include <stdlib.h>
64 #include <string.h>
65 #include <sysexits.h>
66 #include <time.h>
67 #include <unistd.h>
68 #include <devstat.h>
69
70 static struct nlist namelist[] = {
71 #define X_CPTIME        0
72         { "_cp_time" },
73 #define X_BOOTTIME      1
74         { "_boottime" },
75 #define X_HZ            2
76         { "_hz" },
77 #define X_STATHZ        3
78         { "_stathz" },
79 #define X_NCHSTATS      4
80         { "_nchstats" },
81 #define X_INTRNAMES     5
82         { "_intrnames" },
83 #define X_EINTRNAMES    6
84         { "_eintrnames" },
85 #define X_INTRCNT       7
86         { "_intrcnt" },
87 #define X_EINTRCNT      8
88         { "_eintrcnt" },
89 #define X_KMEMSTATISTICS        9
90         { "_kmemstatistics" },
91 #if 0
92 #define X_KMEMBUCKETS   10
93         { "_bucket" },
94 #else
95         { "_kmemstatistics" },
96 #endif
97 #define X_ZLIST         11
98         { "_zlist" },
99 #ifdef notyet
100 #define X_DEFICIT       12
101         { "_deficit" },
102 #define X_FORKSTAT      13
103         { "_forkstat" },
104 #define X_REC           14
105         { "_rectime" },
106 #define X_PGIN          15
107         { "_pgintime" },
108 #define X_XSTATS        16
109         { "_xstats" },
110 #define X_END           17
111 #else
112 #define X_END           12
113 #endif
114         { "" },
115 };
116
117 struct statinfo cur, last;
118 int num_devices, maxshowdevs;
119 long generation;
120 struct device_selection *dev_select;
121 int num_selected;
122 struct devstat_match *matches;
123 int num_matches = 0;
124 int num_devices_specified, num_selections;
125 long select_generation;
126 char **specified_devices;
127 devstat_select_mode select_mode;
128
129 struct  vmmeter vmm, ovmm;
130 struct  vmstats vms, ovms;
131
132 int     winlines = 20;
133 int     nflag = 0;
134
135 kvm_t *kd;
136
137 #define FORKSTAT        0x01
138 #define INTRSTAT        0x02
139 #define MEMSTAT         0x04
140 #define SUMSTAT         0x08
141 #define TIMESTAT        0x10
142 #define VMSTAT          0x20
143 #define ZMEMSTAT        0x40
144
145 void    cpustats(), dointr(), domem(), dosum(), dozmem();
146 void    dovmstat(), kread(), usage();
147 #ifdef notyet
148 void    dotimes(), doforkst();
149 #endif
150 void printhdr(void);
151 static void devstats();
152
153 int
154 main(register int argc, register char **argv)
155 {
156         register int c, todo;
157         u_int interval;
158         int reps;
159         char *memf, *nlistf;
160         char errbuf[_POSIX2_LINE_MAX];
161
162         memf = nlistf = NULL;
163         interval = reps = todo = 0;
164         maxshowdevs = 2;
165         while ((c = getopt(argc, argv, "c:fiM:mN:n:p:stw:z")) != -1) {
166                 switch (c) {
167                 case 'c':
168                         reps = atoi(optarg);
169                         break;
170                 case 'f':
171 #ifdef notyet
172                         todo |= FORKSTAT;
173 #else
174                         errx(EX_USAGE, "sorry, -f is not (re)implemented yet");
175 #endif
176                         break;
177                 case 'i':
178                         todo |= INTRSTAT;
179                         break;
180                 case 'M':
181                         memf = optarg;
182                         break;
183                 case 'm':
184                         todo |= MEMSTAT;
185                         break;
186                 case 'N':
187                         nlistf = optarg;
188                         break;
189                 case 'n':
190                         nflag = 1;
191                         maxshowdevs = atoi(optarg);
192                         if (maxshowdevs < 0)
193                                 errx(1, "number of devices %d is < 0",
194                                      maxshowdevs);
195                         break;
196                 case 'p':
197                         if (buildmatch(optarg, &matches, &num_matches) != 0)
198                                 errx(1, "%s", devstat_errbuf);
199                         break;
200                 case 's':
201                         todo |= SUMSTAT;
202                         break;
203                 case 't':
204 #ifdef notyet
205                         todo |= TIMESTAT;
206 #else
207                         errx(EX_USAGE, "sorry, -t is not (re)implemented yet");
208 #endif
209                         break;
210                 case 'w':
211                         interval = atoi(optarg);
212                         break;
213                 case 'z':
214                         todo |= ZMEMSTAT;
215                         break;
216                 case '?':
217                 default:
218                         usage();
219                 }
220         }
221         argc -= optind;
222         argv += optind;
223
224         if (todo == 0)
225                 todo = VMSTAT;
226
227         /*
228          * Discard setgid privileges if not the running kernel so that bad
229          * guys can't print interesting stuff from kernel memory.
230          */
231         if (nlistf != NULL || memf != NULL)
232                 setgid(getgid());
233
234         kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
235         if (kd == 0) 
236                 errx(1, "kvm_openfiles: %s", errbuf);
237
238         if ((c = kvm_nlist(kd, namelist)) != 0) {
239                 if (c > 0) {
240                         warnx("undefined symbols:");
241                         for (c = 0;
242                             c < sizeof(namelist)/sizeof(namelist[0]); c++)
243                                 if (namelist[c].n_type == 0)
244                                         fprintf(stderr, " %s",
245                                             namelist[c].n_name);
246                         (void)fputc('\n', stderr);
247                 } else
248                         warnx("kvm_nlist: %s", kvm_geterr(kd));
249                 exit(1);
250         }
251
252         if (todo & VMSTAT) {
253                 char **getdrivedata();
254                 struct winsize winsize;
255
256                 /*
257                  * Make sure that the userland devstat version matches the
258                  * kernel devstat version.  If not, exit and print a
259                  * message informing the user of his mistake.
260                  */
261                 if (checkversion() < 0)
262                         errx(1, "%s", devstat_errbuf);
263
264
265                 argv = getdrivedata(argv);
266                 winsize.ws_row = 0;
267                 (void) ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&winsize);
268                 if (winsize.ws_row > 0)
269                         winlines = winsize.ws_row;
270
271         }
272
273 #define BACKWARD_COMPATIBILITY
274 #ifdef  BACKWARD_COMPATIBILITY
275         if (*argv) {
276                 interval = atoi(*argv);
277                 if (*++argv)
278                         reps = atoi(*argv);
279         }
280 #endif
281
282         if (interval) {
283                 if (!reps)
284                         reps = -1;
285         } else if (reps)
286                 interval = 1;
287
288 #ifdef notyet
289         if (todo & FORKSTAT)
290                 doforkst();
291 #endif
292         if (todo & MEMSTAT)
293                 domem();
294         if (todo & ZMEMSTAT)
295                 dozmem();
296         if (todo & SUMSTAT)
297                 dosum();
298 #ifdef notyet
299         if (todo & TIMESTAT)
300                 dotimes();
301 #endif
302         if (todo & INTRSTAT)
303                 dointr();
304         if (todo & VMSTAT)
305                 dovmstat(interval, reps);
306         exit(0);
307 }
308
309 char **
310 getdrivedata(char **argv)
311 {
312         if ((num_devices = getnumdevs()) < 0)
313                 errx(1, "%s", devstat_errbuf);
314
315         cur.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo));
316         last.dinfo = (struct devinfo *)malloc(sizeof(struct devinfo));
317         bzero(cur.dinfo, sizeof(struct devinfo));
318         bzero(last.dinfo, sizeof(struct devinfo));
319
320         if (getdevs(&cur) == -1)
321                 errx(1, "%s", devstat_errbuf);
322
323         num_devices = cur.dinfo->numdevs;
324         generation = cur.dinfo->generation;
325
326         specified_devices = (char **)malloc(sizeof(char *));
327         for (num_devices_specified = 0; *argv; ++argv) {
328                 if (isdigit(**argv))
329                         break;
330                 num_devices_specified++;
331                 specified_devices = (char **)realloc(specified_devices,
332                                                      sizeof(char *) *
333                                                      num_devices_specified);
334                 specified_devices[num_devices_specified - 1] = *argv;
335         }
336         dev_select = NULL;
337
338         if (nflag == 0 && maxshowdevs < num_devices_specified)
339                         maxshowdevs = num_devices_specified;
340
341         /*
342          * People are generally only interested in disk statistics when
343          * they're running vmstat.  So, that's what we're going to give
344          * them if they don't specify anything by default.  We'll also give
345          * them any other random devices in the system so that we get to
346          * maxshowdevs devices, if that many devices exist.  If the user
347          * specifies devices on the command line, either through a pattern
348          * match or by naming them explicitly, we will give the user only
349          * those devices.
350          */
351         if ((num_devices_specified == 0) && (num_matches == 0)) {
352                 if (buildmatch("da", &matches, &num_matches) != 0)
353                         errx(1, "%s", devstat_errbuf);
354
355                 select_mode = DS_SELECT_ADD;
356         } else
357                 select_mode = DS_SELECT_ONLY;
358
359         /*
360          * At this point, selectdevs will almost surely indicate that the
361          * device list has changed, so we don't look for return values of 0
362          * or 1.  If we get back -1, though, there is an error.
363          */
364         if (selectdevs(&dev_select, &num_selected, &num_selections,
365                        &select_generation, generation, cur.dinfo->devices,
366                        num_devices, matches, num_matches, specified_devices,
367                        num_devices_specified, select_mode,
368                        maxshowdevs, 0) == -1)
369                 errx(1, "%s", devstat_errbuf);
370
371         return(argv);
372 }
373
374 long
375 getuptime(void)
376 {
377         static time_t now, boottime;
378         time_t uptime;
379
380         if (boottime == 0)
381                 kread(X_BOOTTIME, &boottime, sizeof(boottime));
382         (void)time(&now);
383         uptime = now - boottime;
384         if (uptime <= 0 || uptime > 60*60*24*365*10)
385                 errx(1, "time makes no sense; namelist must be wrong");
386         return(uptime);
387 }
388
389 int     hz, hdrcnt;
390
391 void
392 dovmstat(u_int interval, int reps)
393 {
394         struct vmtotal total;
395         time_t uptime, halfuptime;
396         struct devinfo *tmp_dinfo;
397         void needhdr();
398         int mib[2];
399         size_t size;
400         int vmm_size = sizeof(vmm);
401         int vms_size = sizeof(vms);
402         int vmt_size = sizeof(total);
403
404         uptime = getuptime();
405         halfuptime = uptime / 2;
406         (void)signal(SIGCONT, needhdr);
407
408         if (namelist[X_STATHZ].n_type != 0 && namelist[X_STATHZ].n_value != 0)
409                 kread(X_STATHZ, &hz, sizeof(hz));
410         if (!hz)
411                 kread(X_HZ, &hz, sizeof(hz));
412
413         for (hdrcnt = 1;;) {
414                 if (!--hdrcnt)
415                         printhdr();
416                 kread(X_CPTIME, cur.cp_time, sizeof(cur.cp_time));
417
418                 tmp_dinfo = last.dinfo;
419                 last.dinfo = cur.dinfo;
420                 cur.dinfo = tmp_dinfo;
421                 last.busy_time = cur.busy_time;
422
423                 /*
424                  * Here what we want to do is refresh our device stats.
425                  * getdevs() returns 1 when the device list has changed.
426                  * If the device list has changed, we want to go through
427                  * the selection process again, in case a device that we
428                  * were previously displaying has gone away.
429                  */
430                 switch (getdevs(&cur)) {
431                 case -1:
432                         errx(1, "%s", devstat_errbuf);
433                         break;
434                 case 1: {
435                         int retval;
436
437                         num_devices = cur.dinfo->numdevs;
438                         generation = cur.dinfo->generation;
439
440                         retval = selectdevs(&dev_select, &num_selected,
441                                             &num_selections, &select_generation,
442                                             generation, cur.dinfo->devices,
443                                             num_devices, matches, num_matches,
444                                             specified_devices,
445                                             num_devices_specified, select_mode,
446                                             maxshowdevs, 0);
447                         switch (retval) {
448                         case -1:
449                                 errx(1, "%s", devstat_errbuf);
450                                 break;
451                         case 1:
452                                 printhdr();
453                                 break;
454                         default:
455                                 break;
456                         }
457                 }
458                 default:
459                         break;
460                 }
461
462                 if (sysctlbyname("vm.vmstats", &vms, &vms_size, NULL, 0)) {
463                         perror("sysctlbyname: vm.vmstats");
464                         exit(1);
465                 }
466                 if (sysctlbyname("vm.vmmeter", &vmm, &vmm_size, NULL, 0)) {
467                         perror("sysctlbyname: vm.vmmeter");
468                         exit(1);
469                 } 
470                 if (sysctlbyname("vm.vmtotal", &total, &vmt_size, NULL, 0)) {
471                         perror("sysctlbyname: vm.vmtotal");
472                         exit(1);
473                 } 
474                 (void)printf("%2d %1d %1d",
475                     total.t_rq - 1, total.t_dw + total.t_pw, total.t_sw);
476 #define vmstat_pgtok(a) ((a) * vms.v_page_size >> 10)
477 #define rate(x) (((x) + halfuptime) / uptime)   /* round */
478                 (void)printf(" %7ld %6ld ",
479                     (long)vmstat_pgtok(total.t_avm), (long)vmstat_pgtok(total.t_free));
480                 (void)printf("%4lu ",
481                     (u_long)rate(vmm.v_vm_faults - ovmm.v_vm_faults));
482                 (void)printf("%3lu ",
483                     (u_long)rate(vmm.v_reactivated - ovmm.v_reactivated));
484                 (void)printf("%3lu ",
485                     (u_long)rate(vmm.v_swapin + vmm.v_vnodein -
486                     (ovmm.v_swapin + ovmm.v_vnodein)));
487                 (void)printf("%3lu ",
488                     (u_long)rate(vmm.v_swapout + vmm.v_vnodeout -
489                     (ovmm.v_swapout + ovmm.v_vnodeout)));
490                 (void)printf("%3lu ",
491                     (u_long)rate(vmm.v_tfree - ovmm.v_tfree));
492                 (void)printf("%3lu ",
493                     (u_long)rate(vmm.v_pdpages - ovmm.v_pdpages));
494                 devstats();
495                 (void)printf("%4lu %4lu %3lu ",
496                     (u_long)rate(vmm.v_intr - ovmm.v_intr),
497                     (u_long)rate(vmm.v_syscall - ovmm.v_syscall),
498                     (u_long)rate(vmm.v_swtch - ovmm.v_swtch));
499                 cpustats();
500                 (void)printf("\n");
501                 (void)fflush(stdout);
502                 if (reps >= 0 && --reps <= 0)
503                         break;
504                 ovmm = vmm;
505                 uptime = interval;
506                 /*
507                  * We round upward to avoid losing low-frequency events
508                  * (i.e., >= 1 per interval but < 1 per second).
509                  */
510                 if (interval != 1)
511                         halfuptime = (uptime + 1) / 2;
512                 else
513                         halfuptime = 0;
514                 (void)sleep(interval);
515         }
516 }
517
518 void
519 printhdr(void)
520 {
521         int i, num_shown;
522
523         num_shown = (num_selected < maxshowdevs) ? num_selected : maxshowdevs;
524         (void)printf(" procs      memory      page%*s", 19, "");
525         if (num_shown > 1)
526                 (void)printf(" disks %*s", num_shown * 4 - 7, "");
527         else if (num_shown == 1)
528                 (void)printf("disk");
529         (void)printf("   faults      cpu\n");
530         (void)printf(" r b w     avm    fre  flt  re  pi  po  fr  sr ");
531         for (i = 0; i < num_devices; i++)
532                 if ((dev_select[i].selected)
533                  && (dev_select[i].selected <= maxshowdevs))
534                         (void)printf("%c%c%d ", dev_select[i].device_name[0],
535                                      dev_select[i].device_name[1],
536                                      dev_select[i].unit_number);
537         (void)printf("  in   sy  cs us sy id\n");
538         hdrcnt = winlines - 2;
539 }
540
541 /*
542  * Force a header to be prepended to the next output.
543  */
544 void
545 needhdr(void)
546 {
547
548         hdrcnt = 1;
549 }
550
551 long
552 pct(long top, long bot)
553 {
554         long ans;
555
556         if (bot == 0)
557                 return(0);
558         ans = (quad_t)top * 100 / bot;
559         return (ans);
560 }
561
562 #define PCT(top, bot) pct((long)(top), (long)(bot))
563
564 void
565 dosum(void)
566 {
567         struct nchstats nchstats;
568         long nchtotal;
569         int vms_size = sizeof(vms);
570         int vmm_size = sizeof(vmm);
571
572         if (sysctlbyname("vm.vmstats", &vms, &vms_size, NULL, 0)) {
573                 perror("sysctlbyname: vm.vmstats");
574                 exit(1);
575         }
576         if (sysctlbyname("vm.vmmeter", &vmm, &vmm_size, NULL, 0)) {
577                 perror("sysctlbyname: vm.vmstats");
578                 exit(1);
579         } 
580         (void)printf("%9u cpu context switches\n", vmm.v_swtch);
581         (void)printf("%9u device interrupts\n", vmm.v_intr);
582         (void)printf("%9u software interrupts\n", vmm.v_soft);
583         (void)printf("%9u traps\n", vmm.v_trap);
584         (void)printf("%9u system calls\n", vmm.v_syscall);
585         (void)printf("%9u kernel threads created\n", vmm.v_kthreads);
586         (void)printf("%9u  fork() calls\n", vmm.v_forks);
587         (void)printf("%9u vfork() calls\n", vmm.v_vforks);
588         (void)printf("%9u rfork() calls\n", vmm.v_rforks);
589         (void)printf("%9u swap pager pageins\n", vmm.v_swapin);
590         (void)printf("%9u swap pager pages paged in\n", vmm.v_swappgsin);
591         (void)printf("%9u swap pager pageouts\n", vmm.v_swapout);
592         (void)printf("%9u swap pager pages paged out\n", vmm.v_swappgsout);
593         (void)printf("%9u vnode pager pageins\n", vmm.v_vnodein);
594         (void)printf("%9u vnode pager pages paged in\n", vmm.v_vnodepgsin);
595         (void)printf("%9u vnode pager pageouts\n", vmm.v_vnodeout);
596         (void)printf("%9u vnode pager pages paged out\n", vmm.v_vnodepgsout);
597         (void)printf("%9u page daemon wakeups\n", vmm.v_pdwakeups);
598         (void)printf("%9u pages examined by the page daemon\n", vmm.v_pdpages);
599         (void)printf("%9u pages reactivated\n", vmm.v_reactivated);
600         (void)printf("%9u copy-on-write faults\n", vmm.v_cow_faults);
601         (void)printf("%9u copy-on-write optimized faults\n", vmm.v_cow_optim);
602         (void)printf("%9u zero fill pages zeroed\n", vmm.v_zfod);
603         (void)printf("%9u zero fill pages prezeroed\n", vmm.v_ozfod);
604         (void)printf("%9u intransit blocking page faults\n", vmm.v_intrans);
605         (void)printf("%9u total VM faults taken\n", vmm.v_vm_faults);
606         (void)printf("%9u pages affected by kernel thread creation\n", vmm.v_kthreadpages);
607         (void)printf("%9u pages affected by  fork()\n", vmm.v_forkpages);
608         (void)printf("%9u pages affected by vfork()\n", vmm.v_vforkpages);
609         (void)printf("%9u pages affected by rfork()\n", vmm.v_rforkpages);
610         (void)printf("%9u pages freed\n", vmm.v_tfree);
611         (void)printf("%9u pages freed by daemon\n", vmm.v_dfree);
612         (void)printf("%9u pages freed by exiting processes\n", vmm.v_pfree);
613         (void)printf("%9u pages active\n", vms.v_active_count);
614         (void)printf("%9u pages inactive\n", vms.v_inactive_count);
615         (void)printf("%9u pages in VM cache\n", vms.v_cache_count);
616         (void)printf("%9u pages wired down\n", vms.v_wire_count);
617         (void)printf("%9u pages free\n", vms.v_free_count);
618         (void)printf("%9u bytes per page\n", vms.v_page_size);
619         kread(X_NCHSTATS, &nchstats, sizeof(nchstats));
620         nchtotal = nchstats.ncs_goodhits + nchstats.ncs_neghits +
621             nchstats.ncs_badhits + nchstats.ncs_falsehits +
622             nchstats.ncs_miss + nchstats.ncs_long;
623         (void)printf("%9ld total name lookups\n", nchtotal);
624         (void)printf(
625             "%9s cache hits (%ld%% pos + %ld%% neg) system %ld%% per-directory\n",
626             "", PCT(nchstats.ncs_goodhits, nchtotal),
627             PCT(nchstats.ncs_neghits, nchtotal),
628             PCT(nchstats.ncs_pass2, nchtotal));
629         (void)printf("%9s deletions %ld%%, falsehits %ld%%, toolong %ld%%\n", "",
630             PCT(nchstats.ncs_badhits, nchtotal),
631             PCT(nchstats.ncs_falsehits, nchtotal),
632             PCT(nchstats.ncs_long, nchtotal));
633 }
634
635 #ifdef notyet
636 void
637 doforkst(void)
638 {
639         struct forkstat fks;
640
641         kread(X_FORKSTAT, &fks, sizeof(struct forkstat));
642         (void)printf("%d forks, %d pages, average %.2f\n",
643             fks.cntfork, fks.sizfork, (double)fks.sizfork / fks.cntfork);
644         (void)printf("%d vforks, %d pages, average %.2f\n",
645             fks.cntvfork, fks.sizvfork, (double)fks.sizvfork / fks.cntvfork);
646 }
647 #endif
648
649 static void
650 devstats(void)
651 {
652         register int dn, state;
653         long double transfers_per_second;
654         long double busy_seconds;
655         long tmp;
656         
657         for (state = 0; state < CPUSTATES; ++state) {
658                 tmp = cur.cp_time[state];
659                 cur.cp_time[state] -= last.cp_time[state];
660                 last.cp_time[state] = tmp;
661         }
662
663         busy_seconds = compute_etime(cur.busy_time, last.busy_time);
664
665         for (dn = 0; dn < num_devices; dn++) {
666                 int di;
667
668                 if ((dev_select[dn].selected == 0)
669                  || (dev_select[dn].selected > maxshowdevs))
670                         continue;
671
672                 di = dev_select[dn].position;
673
674                 if (compute_stats(&cur.dinfo->devices[di],
675                                   &last.dinfo->devices[di], busy_seconds,
676                                   NULL, NULL, NULL,
677                                   NULL, &transfers_per_second, NULL,
678                                   NULL, NULL) != 0)
679                         errx(1, "%s", devstat_errbuf);
680
681                 printf("%3.0Lf ", transfers_per_second);
682         }
683 }
684
685 void
686 cpustats(void)
687 {
688         register int state;
689         double pct, total;
690
691         total = 0;
692         for (state = 0; state < CPUSTATES; ++state)
693                 total += cur.cp_time[state];
694         if (total)
695                 pct = 100 / total;
696         else
697                 pct = 0;
698         (void)printf("%2.0f ", (cur.cp_time[CP_USER] +
699                                 cur.cp_time[CP_NICE]) * pct);
700         (void)printf("%2.0f ", (cur.cp_time[CP_SYS] +
701                                 cur.cp_time[CP_INTR]) * pct);
702         (void)printf("%2.0f", cur.cp_time[CP_IDLE] * pct);
703 }
704
705 void
706 dointr(void)
707 {
708         register u_long *intrcnt, uptime;
709         register u_int64_t inttotal;
710         register int nintr, inamlen;
711         register char *intrname;
712
713         uptime = getuptime();
714         nintr = namelist[X_EINTRCNT].n_value - namelist[X_INTRCNT].n_value;
715         inamlen =
716             namelist[X_EINTRNAMES].n_value - namelist[X_INTRNAMES].n_value;
717         intrcnt = malloc((size_t)nintr);
718         intrname = malloc((size_t)inamlen);
719         if (intrcnt == NULL || intrname == NULL)
720                 errx(1, "malloc");
721         kread(X_INTRCNT, intrcnt, (size_t)nintr);
722         kread(X_INTRNAMES, intrname, (size_t)inamlen);
723         (void)printf("interrupt                   total       rate\n");
724         inttotal = 0;
725         nintr /= sizeof(long);
726         while (--nintr >= 0) {
727                 if (*intrcnt)
728                         (void)printf("%-12s %20lu %10lu\n", intrname,
729                             *intrcnt, *intrcnt / uptime);
730                 intrname += strlen(intrname) + 1;
731                 inttotal += *intrcnt++;
732         }
733         (void)printf("Total        %20llu %10llu\n", inttotal,
734                         inttotal / (u_int64_t) uptime);
735 }
736
737 #define MAX_KMSTATS     200
738
739 void
740 domem(void)
741 {
742         register struct kmembuckets *kp;
743         register struct malloc_type *ks;
744         register int i, j;
745         int len, size, first, nkms;
746         long totuse = 0, totfree = 0, totreq = 0;
747         const char *name;
748         struct malloc_type kmemstats[MAX_KMSTATS], *kmsp;
749         char buf[1024];
750         struct kmembuckets buckets[MINBUCKET + 16];
751
752 #ifdef X_KMEMBUCKETS
753         kread(X_KMEMBUCKETS, buckets, sizeof(buckets));
754 #else
755         bzero(buckets, sizeof(buckets));
756 #endif
757         kread(X_KMEMSTATISTICS, &kmsp, sizeof(kmsp));
758         for (nkms = 0; nkms < MAX_KMSTATS && kmsp != NULL; nkms++) {
759                 if (sizeof(kmemstats[0]) != kvm_read(kd, (u_long)kmsp,
760                     &kmemstats[nkms], sizeof(kmemstats[0])))
761                         err(1, "kvm_read(%p)", (void *)kmsp);
762                 if (sizeof(buf) !=  kvm_read(kd, 
763                     (u_long)kmemstats[nkms].ks_shortdesc, buf, sizeof(buf)))
764                         err(1, "kvm_read(%p)", 
765                             (void *)kmemstats[nkms].ks_shortdesc);
766                 buf[sizeof(buf) - 1] = '\0';
767                 kmemstats[nkms].ks_shortdesc = strdup(buf);
768                 kmsp = kmemstats[nkms].ks_next;
769         }
770         if (kmsp != NULL)
771                 warnx("truncated to the first %d memory types", nkms);
772         (void)printf("Memory statistics by bucket size\n");
773         (void)printf(
774             "Size   In Use   Free   Requests  HighWater  Couldfree\n");
775         for (i = MINBUCKET, kp = &buckets[i]; i < MINBUCKET + 16; i++, kp++) {
776                 if (kp->kb_calls == 0)
777                         continue;
778                 size = 1 << i;
779                 if(size < 1024)
780                         (void)printf("%4d",size);
781                 else
782                         (void)printf("%3dK",size>>10);
783                 (void)printf(" %8ld %6ld %10lld %7ld %10ld\n",
784                         kp->kb_total - kp->kb_totalfree,
785                         kp->kb_totalfree, kp->kb_calls,
786                         kp->kb_highwat, kp->kb_couldfree);
787                 totfree += size * kp->kb_totalfree;
788         }
789
790         (void)printf("\nMemory usage type by bucket size\n");
791         (void)printf("Size  Type(s)\n");
792         kp = &buckets[MINBUCKET];
793         for (j =  1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1, kp++) {
794                 if (kp->kb_calls == 0)
795                         continue;
796                 first = 1;
797                 len = 8;
798                 for (i = 0, ks = &kmemstats[0]; i < nkms; i++, ks++) {
799                         if (ks->ks_calls == 0)
800                                 continue;
801                         if ((ks->ks_size & j) == 0)
802                                 continue;
803                         name = ks->ks_shortdesc;
804                         len += 2 + strlen(name);
805                         if (first && j < 1024)
806                                 printf("%4d  %s", j, name);
807                         else if (first)
808                                 printf("%3dK  %s", j>>10, name);
809                         else
810                                 printf(",");
811                         if (len >= 79) {
812                                 printf("\n\t ");
813                                 len = 10 + strlen(name);
814                         }
815                         if (!first)
816                                 printf(" %s", name);
817                         first = 0;
818                 }
819                 printf("\n");
820         }
821
822         (void)printf(
823             "\nMemory statistics by type                          Type  Kern\n");
824         (void)printf(
825 "        Type  InUse MemUse HighUse  Limit Requests Limit Limit Size(s)\n");
826         for (i = 0, ks = &kmemstats[0]; i < nkms; i++, ks++) {
827                 if (ks->ks_calls == 0)
828                         continue;
829                 (void)printf("%13s%6ld%6ldK%7ldK%6ldK%9lld%5u%6u",
830                     ks->ks_shortdesc,
831                     ks->ks_inuse, (ks->ks_memuse + 1023) / 1024,
832                     (ks->ks_maxused + 1023) / 1024,
833                     (ks->ks_limit + 1023) / 1024, ks->ks_calls,
834                     ks->ks_limblocks, ks->ks_mapblocks);
835                 first = 1;
836                 for (j =  1 << MINBUCKET; j < 1 << (MINBUCKET + 16); j <<= 1) {
837                         if ((ks->ks_size & j) == 0)
838                                 continue;
839                         if (first)
840                                 printf("  ");
841                         else
842                                 printf(",");
843                         if(j<1024)
844                                 printf("%d",j);
845                         else
846                                 printf("%dK",j>>10);
847                         first = 0;
848                 }
849                 printf("\n");
850                 totuse += ks->ks_memuse;
851                 totreq += ks->ks_calls;
852         }
853         (void)printf("\nMemory Totals:  In Use    Free    Requests\n");
854         (void)printf("              %7ldK %6ldK    %8ld\n",
855              (totuse + 1023) / 1024, (totfree + 1023) / 1024, totreq);
856 }
857
858 void
859 dozmem(void)
860 {
861         char *buf;
862         size_t bufsize;
863
864         buf = NULL;
865         bufsize = 1024;
866         for (;;) {
867                 if ((buf = realloc(buf, bufsize)) == NULL)
868                         err(1, "realloc()");
869                 if (sysctlbyname("vm.zone", buf, &bufsize, 0, NULL) == 0)
870                         break;
871                 if (errno != ENOMEM)
872                         err(1, "sysctl()");
873                 bufsize *= 2;
874         }
875         buf[bufsize] = '\0'; /* play it safe */
876         (void)printf("%s\n\n", buf);
877         free(buf);
878 }
879
880 /*
881  * kread reads something from the kernel, given its nlist index.
882  */
883 void
884 kread(int nlx, void *addr, size_t size)
885 {
886         char *sym;
887
888         if (namelist[nlx].n_type == 0 || namelist[nlx].n_value == 0) {
889                 sym = namelist[nlx].n_name;
890                 if (*sym == '_')
891                         ++sym;
892                 errx(1, "symbol %s not defined", sym);
893         }
894         if (kvm_read(kd, namelist[nlx].n_value, addr, size) != size) {
895                 sym = namelist[nlx].n_name;
896                 if (*sym == '_')
897                         ++sym;
898                 errx(1, "%s: %s", sym, kvm_geterr(kd));
899         }
900 }
901
902 void
903 usage(void)
904 {
905         (void)fprintf(stderr, "%s%s",
906                 "usage: vmstat [-imsz] [-c count] [-M core] [-N system] [-w wait]\n",
907                 "              [-n devs] [disks]\n");
908         exit(1);
909 }