]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/systat/vmstat.c
bluetooth: Fix a mandoc related issues
[FreeBSD/FreeBSD.git] / usr.bin / systat / vmstat.c
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1983, 1989, 1992, 1993
5  *      The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 #include <sys/cdefs.h>
33
34 __FBSDID("$FreeBSD$");
35
36 #ifdef lint
37 static const char sccsid[] = "@(#)vmstat.c      8.2 (Berkeley) 1/12/94";
38 #endif
39
40 /*
41  * Cursed vmstat -- from Robert Elz.
42  */
43
44 #include <sys/param.h>
45 #include <sys/stat.h>
46 #include <sys/time.h>
47 #include <sys/proc.h>
48 #include <sys/uio.h>
49 #include <sys/namei.h>
50 #include <sys/resource.h>
51 #include <sys/sysctl.h>
52 #include <sys/vmmeter.h>
53
54 #include <vm/vm_param.h>
55
56 #include <ctype.h>
57 #include <err.h>
58 #include <errno.h>
59 #include <langinfo.h>
60 #include <libutil.h>
61 #include <nlist.h>
62 #include <paths.h>
63 #include <signal.h>
64 #include <stdlib.h>
65 #include <string.h>
66 #include <time.h>
67 #include <unistd.h>
68 #include <utmpx.h>
69 #include "systat.h"
70 #include "extern.h"
71 #include "devs.h"
72
73 static struct Info {
74         long    time[CPUSTATES];
75         uint64_t v_swtch;       /* context switches */
76         uint64_t v_trap;        /* calls to trap */
77         uint64_t v_syscall;     /* calls to syscall() */
78         uint64_t v_intr;        /* device interrupts */
79         uint64_t v_soft;        /* software interrupts */
80         /*
81          * Virtual memory activity.
82          */
83         uint64_t v_vm_faults;   /* number of address memory faults */
84         uint64_t v_io_faults;   /* page faults requiring I/O */
85         uint64_t v_cow_faults;  /* number of copy-on-writes */
86         uint64_t v_zfod;        /* pages zero filled on demand */
87         uint64_t v_ozfod;       /* optimized zero fill pages */
88         uint64_t v_swapin;      /* swap pager pageins */
89         uint64_t v_swapout;     /* swap pager pageouts */
90         uint64_t v_swappgsin;   /* swap pager pages paged in */
91         uint64_t v_swappgsout;  /* swap pager pages paged out */
92         uint64_t v_vnodein;     /* vnode pager pageins */
93         uint64_t v_vnodeout;    /* vnode pager pageouts */
94         uint64_t v_vnodepgsin;  /* vnode_pager pages paged in */
95         uint64_t v_vnodepgsout; /* vnode pager pages paged out */
96         uint64_t v_intrans;     /* intransit blocking page faults */
97         uint64_t v_reactivated; /* number of pages reactivated by pagedaemon */
98         uint64_t v_pdwakeups;   /* number of times daemon has awaken from sleep */
99         uint64_t v_pdpages;     /* number of pages analyzed by daemon */
100
101         uint64_t v_dfree;       /* pages freed by daemon */
102         uint64_t v_pfree;       /* pages freed by exiting processes */
103         uint64_t v_tfree;       /* total pages freed */
104         /*
105          * Distribution of page usages.
106          */
107         u_int v_free_count;     /* number of pages free */
108         u_int v_wire_count;     /* number of pages wired down */
109         u_int v_active_count;   /* number of pages active */
110         u_int v_inactive_count; /* number of pages inactive */
111         u_int v_laundry_count;  /* number of pages in laundry queue */
112         u_long v_kmem_map_size; /* Current kmem allocation size */
113         struct  vmtotal Total;
114         struct  nchstats nchstats;
115         long    nchcount;
116         long    *intrcnt;
117         long    bufspace;
118         u_long  maxvnodes;
119         long    numvnodes;
120         long    freevnodes;
121         int     numdirtybuffers;
122 } s, s1, s2, z;
123 static u_long kmem_size;
124 static u_int v_page_count;
125
126
127 #define total s.Total
128 #define nchtotal s.nchstats
129 #define oldnchtotal s1.nchstats
130
131 static  enum state { BOOT, TIME, RUN } state = TIME;
132 enum divisor { IEC = 0, SI = HN_DIVISOR_1000 };
133
134 static void allocinfo(struct Info *);
135 static void copyinfo(struct Info *, struct Info *);
136 static float cputime(int);
137 static void do_putuint64(uint64_t, int, int, int, int);
138 static void getinfo(struct Info *);
139 static void putuint64(uint64_t, int, int, int);
140 static int ucount(void);
141
142 static  int ncpu;
143 static  char buf[26];
144 static  time_t t;
145 static  double etime;
146 static  int nintr;
147 static  long *intrloc;
148 static  char **intrname;
149 static  int nextintsrow;
150
151 WINDOW *
152 openkre(void)
153 {
154
155         return (stdscr);
156 }
157
158 void
159 closekre(WINDOW *w)
160 {
161
162         if (w == NULL)
163                 return;
164         wclear(w);
165         wrefresh(w);
166 }
167
168 /*
169  * These constants define where the major pieces are laid out
170  */
171 #define STATROW          0      /* uses 1 row and 67 cols */
172 #define STATCOL          0
173 #define MEMROW           2      /* uses 4 rows and 45 cols */
174 #define MEMCOL           0
175 #define PAGEROW          1      /* uses 4 rows and 30 cols */
176 #define PAGECOL         47
177 #define INTSROW          5      /* uses all rows to bottom and 16 cols */
178 #define INTSCOL         64
179 #define PROCSROW         6      /* uses 3 rows and 19 cols */
180 #define PROCSCOL         0
181 #define GENSTATROW       7      /* uses 2 rows and 29 cols */
182 #define GENSTATCOL      21
183 #define VMSTATROW        5      /* uses 17 rows and 12-14 cols */
184 #define VMSTATCOL       49      /* actually 50-51 for some fields */
185 #define GRAPHROW        10      /* uses 3 rows and 49-51 cols */
186 #define GRAPHCOL         0
187 #define VNSTATROW       13      /* uses 4 rows and 13 columns */
188 #define VNSTATCOL       35
189 #define NAMEIROW        14      /* uses 3 rows and 32 cols */
190 #define NAMEICOL         0
191 #define DISKROW         18      /* uses 5 rows and 47 cols (for 7 drives) */
192 #define DISKCOL          0
193
194 #define DRIVESPACE       7      /* max # for space */
195
196 #define MAXDRIVES       DRIVESPACE       /* max # to display */
197
198 int
199 initkre(void)
200 {
201         char *cp, *cp1, *cp2, *intrnamebuf, *nextcp;
202         int i;
203         size_t sz;
204
205         if (dsinit(MAXDRIVES) != 1)
206                 return(0);
207
208         if (nintr == 0) {
209                 if (sysctlbyname("hw.intrcnt", NULL, &sz, NULL, 0) == -1) {
210                         error("sysctl(hw.intrcnt...) failed: %s",
211                               strerror(errno));
212                         return (0);
213                 }
214                 nintr = sz / sizeof(u_long);
215                 intrloc = calloc(nintr, sizeof (long));
216                 intrname = calloc(nintr, sizeof (char *));
217                 intrnamebuf = sysctl_dynread("hw.intrnames", NULL);
218                 if (intrnamebuf == NULL || intrname == NULL ||
219                     intrloc == NULL) {
220                         error("Out of memory");
221                         if (intrnamebuf)
222                                 free(intrnamebuf);
223                         if (intrname)
224                                 free(intrname);
225                         if (intrloc)
226                                 free(intrloc);
227                         nintr = 0;
228                         return(0);
229                 }
230                 for (cp = intrnamebuf, i = 0; i < nintr; i++) {
231                         nextcp = cp + strlen(cp) + 1;
232
233                         /* Discard trailing spaces. */
234                         for (cp1 = nextcp - 1; cp1 > cp && *(cp1 - 1) == ' '; )
235                                 *--cp1 = '\0';
236
237                         /* Convert "irqN: name" to "name irqN". */
238                         if (strncmp(cp, "irq", 3) == 0) {
239                                 cp1 = cp + 3;
240                                 while (isdigit((u_char)*cp1))
241                                         cp1++;
242                                 if (cp1 != cp && *cp1 == ':' &&
243                                     *(cp1 + 1) == ' ') {
244                                         sz = strlen(cp);
245                                         *cp1 = '\0';
246                                         cp1 = cp1 + 2;
247                                         cp2 = strdup(cp);
248                                         bcopy(cp1, cp, sz - (cp1 - cp) + 1);
249                                         if (sz <= 10 + 4) {
250                                                 strcat(cp, " ");
251                                                 strcat(cp, cp2 + 3);
252                                         }
253                                         free(cp2);
254                                 }
255                         }
256
257                         /*
258                          * Convert "name irqN" to "name N" if the former is
259                          * longer than the field width.
260                          */
261                         if ((cp1 = strstr(cp, "irq")) != NULL &&
262                             strlen(cp) > 10)
263                                 bcopy(cp1 + 3, cp1, strlen(cp1 + 3) + 1);
264
265                         intrname[i] = cp;
266                         cp = nextcp;
267                 }
268                 nextintsrow = INTSROW + 2;
269                 allocinfo(&s);
270                 allocinfo(&s1);
271                 allocinfo(&s2);
272                 allocinfo(&z);
273         }
274         GETSYSCTL("vm.kmem_size", kmem_size);
275         GETSYSCTL("vm.stats.vm.v_page_count", v_page_count);
276         getinfo(&s2);
277         copyinfo(&s2, &s1);
278         return(1);
279 }
280
281 void
282 fetchkre(void)
283 {
284         time_t now;
285         struct tm *tp;
286         static int d_first = -1;
287
288         if (d_first < 0)
289                 d_first = (*nl_langinfo(D_MD_ORDER) == 'd');
290
291         time(&now);
292         tp = localtime(&now);
293         (void) strftime(buf, sizeof(buf),
294                         d_first ? "%e %b %R" : "%b %e %R", tp);
295         getinfo(&s);
296 }
297
298 void
299 labelkre(void)
300 {
301         int i, j;
302
303         clear();
304         mvprintw(STATROW, STATCOL + 6, "users    Load");
305         mvprintw(STATROW + 1, STATCOL + 3, "Mem usage:    %%Phy   %%Kmem");
306         mvprintw(MEMROW, MEMCOL, "Mem:      REAL           VIRTUAL");
307         mvprintw(MEMROW + 1, MEMCOL, "       Tot   Share     Tot    Share");
308         mvprintw(MEMROW + 2, MEMCOL, "Act");
309         mvprintw(MEMROW + 3, MEMCOL, "All");
310
311         mvprintw(MEMROW + 1, MEMCOL + 40, "Free");
312
313         mvprintw(PAGEROW, PAGECOL,     "         VN PAGER   SWAP PAGER");
314         mvprintw(PAGEROW + 1, PAGECOL, "         in   out     in   out");
315         mvprintw(PAGEROW + 2, PAGECOL, "count");
316         mvprintw(PAGEROW + 3, PAGECOL, "pages");
317
318         mvprintw(INTSROW, INTSCOL + 1, "Interrupts");
319         mvprintw(INTSROW + 1, INTSCOL + 6, "total");
320
321         mvprintw(VMSTATROW, VMSTATCOL + 9, "ioflt");
322         mvprintw(VMSTATROW + 1, VMSTATCOL + 9, "cow");
323         mvprintw(VMSTATROW + 2, VMSTATCOL + 9, "zfod");
324         mvprintw(VMSTATROW + 3, VMSTATCOL + 9, "ozfod");
325         mvprintw(VMSTATROW + 4, VMSTATCOL + 9 - 1, "%%ozfod");
326         mvprintw(VMSTATROW + 5, VMSTATCOL + 9, "daefr");
327         mvprintw(VMSTATROW + 6, VMSTATCOL + 9, "prcfr");
328         mvprintw(VMSTATROW + 7, VMSTATCOL + 9, "totfr");
329         mvprintw(VMSTATROW + 8, VMSTATCOL + 9, "react");
330         mvprintw(VMSTATROW + 9, VMSTATCOL + 9, "pdwak");
331         mvprintw(VMSTATROW + 10, VMSTATCOL + 9, "pdpgs");
332         mvprintw(VMSTATROW + 11, VMSTATCOL + 9, "intrn");
333         mvprintw(VMSTATROW + 12, VMSTATCOL + 9, "wire");
334         mvprintw(VMSTATROW + 13, VMSTATCOL + 9, "act");
335         mvprintw(VMSTATROW + 14, VMSTATCOL + 9, "inact");
336         mvprintw(VMSTATROW + 15, VMSTATCOL + 9, "laund");
337         mvprintw(VMSTATROW + 16, VMSTATCOL + 9, "free");
338         if (LINES - 1 > VMSTATROW + 17)
339                 mvprintw(VMSTATROW + 17, VMSTATCOL + 9, "buf");
340
341         mvprintw(GENSTATROW, GENSTATCOL, " Csw  Trp  Sys  Int  Sof  Flt");
342
343         mvprintw(GRAPHROW, GRAPHCOL,
344                 "  . %%Sys    . %%Intr   . %%User   . %%Nice   . %%Idle");
345         mvprintw(PROCSROW, PROCSCOL, "Proc:");
346         mvprintw(PROCSROW + 1, PROCSCOL, "  r   p   d   s   w");
347         mvprintw(GRAPHROW + 1, GRAPHCOL,
348                 "|    |    |    |    |    |    |    |    |    |    |");
349
350         mvprintw(VNSTATROW, VNSTATCOL + 8, "dtbuf");
351         mvprintw(VNSTATROW + 1, VNSTATCOL + 8, "maxvn");
352         mvprintw(VNSTATROW + 2, VNSTATCOL + 8, "numvn");
353         mvprintw(VNSTATROW + 3, VNSTATCOL + 8, "frevn");
354
355         mvprintw(NAMEIROW, NAMEICOL, "Namei     Name-cache   Dir-cache");
356         mvprintw(NAMEIROW + 1, NAMEICOL,
357                 "   Calls    hits   %%    hits   %%");
358         dslabel(MAXDRIVES, DISKCOL, DISKROW);
359
360         for (i = 0; i < nintr; i++) {
361                 if (intrloc[i] == 0)
362                         continue;
363                 mvprintw(intrloc[i], INTSCOL + 6, "%-10.10s", intrname[i]);
364         }
365 }
366
367 #define X(fld)  {t=s.fld[i]; s.fld[i]-=s1.fld[i]; if(state==TIME) s1.fld[i]=t;}
368 #define Q(fld)  {t=cur_dev.fld[i]; cur_dev.fld[i]-=last_dev.fld[i]; if(state==TIME) last_dev.fld[i]=t;}
369 #define Y(fld)  {t = s.fld; s.fld -= s1.fld; if(state == TIME) s1.fld = t;}
370 #define Z(fld)  {t = s.nchstats.fld; s.nchstats.fld -= s1.nchstats.fld; \
371         if(state == TIME) s1.nchstats.fld = t;}
372 #define PUTRATE(fld, l, c, w) \
373 do { \
374         Y(fld); \
375         sysputwuint64(wnd, l, c, w, (s.fld/etime + 0.5), 0); \
376 } while (0)
377 #define MAXFAIL 5
378
379 static  char cpuchar[CPUSTATES] = { '=' , '+', '>', '-', ' ' };
380 static  char cpuorder[CPUSTATES] = { CP_SYS, CP_INTR, CP_USER, CP_NICE,
381                                      CP_IDLE };
382
383 void
384 showkre(void)
385 {
386         float f1, f2;
387         int psiz, inttotal;
388         int i, l, lc;
389         static int failcnt = 0;
390
391         etime = 0;
392         for(i = 0; i < CPUSTATES; i++) {
393                 X(time);
394                 Q(cp_time);
395                 etime += s.time[i];
396         }
397         if (etime < 5.0) {      /* < 5 ticks - ignore this trash */
398                 if (failcnt++ >= MAXFAIL) {
399                         clear();
400                         mvprintw(2, 10, "The alternate system clock has died!");
401                         mvprintw(3, 10, "Reverting to ``pigs'' display.");
402                         move(CMDLINE, 0);
403                         refresh();
404                         failcnt = 0;
405                         sleep(5);
406                         command("pigs");
407                 }
408                 return;
409         }
410         failcnt = 0;
411         etime /= hertz;
412         etime /= ncpu;
413         inttotal = 0;
414         for (i = 0; i < nintr; i++) {
415                 if (s.intrcnt[i] == 0)
416                         continue;
417                 X(intrcnt);
418                 l = (int)((float)s.intrcnt[i]/etime + 0.5);
419                 inttotal += l;
420                 if (intrloc[i] == 0) {
421                         if (nextintsrow == LINES)
422                                 continue;
423                         intrloc[i] = nextintsrow++;
424                         mvprintw(intrloc[i], INTSCOL + 6, "%-10.10s",
425                                 intrname[i]);
426                 }
427                 putint(l, intrloc[i], INTSCOL, 5);
428         }
429         putint(inttotal, INTSROW + 1, INTSCOL, 5);
430         Z(ncs_goodhits); Z(ncs_badhits); Z(ncs_miss);
431         Z(ncs_long); Z(ncs_pass2); Z(ncs_2passes); Z(ncs_neghits);
432         s.nchcount = nchtotal.ncs_goodhits + nchtotal.ncs_badhits +
433             nchtotal.ncs_miss + nchtotal.ncs_long + nchtotal.ncs_neghits;
434         if (state == TIME)
435                 s1.nchcount = s.nchcount;
436
437         psiz = 0;
438         f2 = 0.0;
439         for (lc = 0; lc < CPUSTATES; lc++) {
440                 i = cpuorder[lc];
441                 f1 = cputime(i);
442                 f2 += f1;
443                 l = (int) ((f2 + 1.0) / 2.0) - psiz;
444                 putfloat(f1, GRAPHROW, GRAPHCOL + 10 * lc, 4, 1, 0);
445                 move(GRAPHROW + 2, psiz);
446                 psiz += l;
447                 while (l-- > 0)
448                         addch(cpuchar[lc]);
449         }
450
451         putint(ucount(), STATROW, STATCOL, 5);
452         putfloat(avenrun[0], STATROW, STATCOL + 20, 5, 2, 0);
453         putfloat(avenrun[1], STATROW, STATCOL + 26, 5, 2, 0);
454         putfloat(avenrun[2], STATROW, STATCOL + 32, 5, 2, 0);
455         mvaddstr(STATROW, STATCOL + 55, buf);
456         putfloat(100.0 * (v_page_count - total.t_free) / v_page_count,
457            STATROW + 1, STATCOL + 15, 2, 0, 1);
458         putfloat(100.0 * s.v_kmem_map_size / kmem_size,
459            STATROW + 1, STATCOL + 22, 2, 0, 1);
460
461         sysputpage(wnd, MEMROW + 2, MEMCOL + 4, 6, total.t_arm, 0);
462         sysputpage(wnd, MEMROW + 2, MEMCOL + 12, 6, total.t_armshr, 0);
463         sysputpage(wnd, MEMROW + 2, MEMCOL + 20, 6, total.t_avm, 0);
464         sysputpage(wnd, MEMROW + 2, MEMCOL + 29, 6, total.t_avmshr, 0);
465         sysputpage(wnd, MEMROW + 3, MEMCOL + 4, 6, total.t_rm, 0);
466         sysputpage(wnd, MEMROW + 3, MEMCOL + 12, 6, total.t_rmshr, 0);
467         sysputpage(wnd, MEMROW + 3, MEMCOL + 20, 6, total.t_vm, 0);
468         sysputpage(wnd, MEMROW + 3, MEMCOL + 29, 6, total.t_vmshr, 0);
469         sysputpage(wnd, MEMROW + 2, MEMCOL + 38, 6, total.t_free, 0);
470         putint(total.t_rq - 1, PROCSROW + 2, PROCSCOL, 3);
471         putint(total.t_pw, PROCSROW + 2, PROCSCOL + 4, 3);
472         putint(total.t_dw, PROCSROW + 2, PROCSCOL + 8, 3);
473         putint(total.t_sl, PROCSROW + 2, PROCSCOL + 12, 3);
474         putint(total.t_sw, PROCSROW + 2, PROCSCOL + 16, 3);
475         PUTRATE(v_io_faults, VMSTATROW, VMSTATCOL + 2, 8 - 2);
476         PUTRATE(v_cow_faults, VMSTATROW + 1, VMSTATCOL + 2, 8 - 2);
477         PUTRATE(v_zfod, VMSTATROW + 2, VMSTATCOL + 2, 8 - 2);
478         PUTRATE(v_ozfod, VMSTATROW + 3, VMSTATCOL, 8);
479         putint(s.v_zfod != 0 ? (int)(s.v_ozfod * 100.0 / s.v_zfod) : 0,
480             VMSTATROW + 4, VMSTATCOL + 1, 8 - 1);
481         PUTRATE(v_dfree, VMSTATROW + 5, VMSTATCOL + 2, 8 - 2);
482         PUTRATE(v_pfree, VMSTATROW + 6, VMSTATCOL + 2, 8 - 2);
483         PUTRATE(v_tfree, VMSTATROW + 7, VMSTATCOL, 8);
484         PUTRATE(v_reactivated, VMSTATROW + 8, VMSTATCOL, 8);
485         PUTRATE(v_pdwakeups, VMSTATROW + 9, VMSTATCOL, 8);
486         PUTRATE(v_pdpages, VMSTATROW + 10, VMSTATCOL, 8);
487         PUTRATE(v_intrans, VMSTATROW + 11, VMSTATCOL, 8);
488         sysputpage(wnd, VMSTATROW + 12, VMSTATCOL + 2, 8 - 2, s.v_wire_count, 0);
489         sysputpage(wnd, VMSTATROW + 13, VMSTATCOL + 2, 8 - 2, s.v_active_count, 0);
490         sysputpage(wnd, VMSTATROW + 14, VMSTATCOL + 2, 8 - 2, s.v_inactive_count, 0);
491         sysputpage(wnd, VMSTATROW + 15, VMSTATCOL + 2, 8 - 2, s.v_laundry_count, 0);
492         sysputpage(wnd, VMSTATROW + 16, VMSTATCOL + 2, 8 - 2, s.v_free_count, 0);
493         if (LINES - 1 > VMSTATROW + 17)
494                 sysputuint64(wnd, VMSTATROW + 17, VMSTATCOL + 2, 8 - 2, s.bufspace, 0);
495         PUTRATE(v_vnodein, PAGEROW + 2, PAGECOL + 6, 5);
496         PUTRATE(v_vnodeout, PAGEROW + 2, PAGECOL + 12, 5);
497         PUTRATE(v_swapin, PAGEROW + 2, PAGECOL + 19, 5);
498         PUTRATE(v_swapout, PAGEROW + 2, PAGECOL + 25, 5);
499         PUTRATE(v_vnodepgsin, PAGEROW + 3, PAGECOL + 6, 5);
500         PUTRATE(v_vnodepgsout, PAGEROW + 3, PAGECOL + 12, 5);
501         PUTRATE(v_swappgsin, PAGEROW + 3, PAGECOL + 19, 5);
502         PUTRATE(v_swappgsout, PAGEROW + 3, PAGECOL + 25, 5);
503         PUTRATE(v_swtch, GENSTATROW + 1, GENSTATCOL, 4);
504         PUTRATE(v_trap, GENSTATROW + 1, GENSTATCOL + 5, 4);
505         PUTRATE(v_syscall, GENSTATROW + 1, GENSTATCOL + 10, 4);
506         PUTRATE(v_intr, GENSTATROW + 1, GENSTATCOL + 15, 4);
507         PUTRATE(v_soft, GENSTATROW + 1, GENSTATCOL + 20, 4);
508         PUTRATE(v_vm_faults, GENSTATROW + 1, GENSTATCOL + 25, 4);
509         switch(state) {
510         case TIME:
511                 dsshow(MAXDRIVES, DISKCOL, DISKROW, &cur_dev, &last_dev);
512                 break;
513         case RUN:
514                 dsshow(MAXDRIVES, DISKCOL, DISKROW, &cur_dev, &run_dev);
515                 break;
516         case BOOT:
517                 dsshow(MAXDRIVES, DISKCOL, DISKROW, &cur_dev, NULL);
518                 break;
519         }
520         putint(s.numdirtybuffers, VNSTATROW, VNSTATCOL, 7);
521         putint(s.maxvnodes, VNSTATROW + 1, VNSTATCOL, 7);
522         putint(s.numvnodes, VNSTATROW + 2, VNSTATCOL, 7);
523         putint(s.freevnodes, VNSTATROW + 3, VNSTATCOL, 7);
524         putint(s.nchcount, NAMEIROW + 2, NAMEICOL, 8);
525         putint((nchtotal.ncs_goodhits + nchtotal.ncs_neghits),
526            NAMEIROW + 2, NAMEICOL + 9, 7);
527 #define nz(x)   ((x) ? (x) : 1)
528         putfloat((nchtotal.ncs_goodhits+nchtotal.ncs_neghits) *
529            100.0 / nz(s.nchcount),
530            NAMEIROW + 2, NAMEICOL + 17, 3, 0, 1);
531         putint(nchtotal.ncs_pass2, NAMEIROW + 2, NAMEICOL + 21, 7);
532         putfloat(nchtotal.ncs_pass2 * 100.0 / nz(s.nchcount),
533            NAMEIROW + 2, NAMEICOL + 29, 3, 0, 1);
534 #undef nz
535 }
536
537 int
538 cmdkre(const char *cmd, const char *args)
539 {
540         int retval;
541
542         if (prefix(cmd, "run")) {
543                 retval = 1;
544                 copyinfo(&s2, &s1);
545                 switch (devstat_getdevs(NULL, &run_dev)) {
546                 case -1:
547                         errx(1, "%s", devstat_errbuf);
548                         break;
549                 case 1:
550                         num_devices = run_dev.dinfo->numdevs;
551                         generation = run_dev.dinfo->generation;
552                         retval = dscmd("refresh", NULL, MAXDRIVES, &cur_dev);
553                         if (retval == 2)
554                                 labelkre();
555                         break;
556                 default:
557                         break;
558                 }
559                 state = RUN;
560                 return (retval);
561         }
562         if (prefix(cmd, "boot")) {
563                 state = BOOT;
564                 copyinfo(&z, &s1);
565                 return (1);
566         }
567         if (prefix(cmd, "time")) {
568                 state = TIME;
569                 return (1);
570         }
571         if (prefix(cmd, "zero")) {
572                 retval = 1;
573                 if (state == RUN) {
574                         getinfo(&s1);
575                         switch (devstat_getdevs(NULL, &run_dev)) {
576                         case -1:
577                                 errx(1, "%s", devstat_errbuf);
578                                 break;
579                         case 1:
580                                 num_devices = run_dev.dinfo->numdevs;
581                                 generation = run_dev.dinfo->generation;
582                                 retval = dscmd("refresh",NULL, MAXDRIVES, &cur_dev);
583                                 if (retval == 2)
584                                         labelkre();
585                                 break;
586                         default:
587                                 break;
588                         }
589                 }
590                 return (retval);
591         }
592         retval = dscmd(cmd, args, MAXDRIVES, &cur_dev);
593
594         if (retval == 2)
595                 labelkre();
596
597         return(retval);
598 }
599
600 /* calculate number of users on the system */
601 static int
602 ucount(void)
603 {
604         int nusers = 0;
605         struct utmpx *ut;
606
607         setutxent();
608         while ((ut = getutxent()) != NULL)
609                 if (ut->ut_type == USER_PROCESS)
610                         nusers++;
611         endutxent();
612
613         return (nusers);
614 }
615
616 static float
617 cputime(int indx)
618 {
619         double lt;
620         int i;
621
622         lt = 0;
623         for (i = 0; i < CPUSTATES; i++)
624                 lt += s.time[i];
625         if (lt == 0.0)
626                 lt = 1.0;
627         return (s.time[indx] * 100.0 / lt);
628 }
629
630 void
631 putint(int n, int l, int lc, int w)
632 {
633
634         do_putuint64(n, l, lc, w, SI);
635 }
636
637 static void
638 putuint64(uint64_t n, int l, int lc, int w)
639 {
640
641         do_putuint64(n, l, lc, w, IEC);
642 }
643
644 static void
645 do_putuint64(uint64_t n, int l, int lc, int w, int div)
646 {
647         int snr;
648         char b[128];
649         char buf[128];
650
651         move(l, lc);
652 #ifdef DEBUG
653                 while (w-- > 0)
654                         addch('*');
655                 return;
656 #endif
657         if (n == 0) {
658                 while (w-- > 0)
659                         addch(' ');
660                 return;
661         }
662         snr = snprintf(b, sizeof(b), "%*ju", w, (uintmax_t)n);
663         if (snr != w) {
664                 humanize_number(buf, w, n, "", HN_AUTOSCALE,
665                     HN_NOSPACE | HN_DECIMAL | div);
666                 snr = snprintf(b, sizeof(b), "%*s", w, buf);
667         }
668         if (snr != w) {
669                 while (w-- > 0)
670                         addch('*');
671                 return;
672         }
673         addstr(b);
674 }
675
676 void
677 putfloat(double f, int l, int lc, int w, int d, int nz)
678 {
679         int snr;
680         char b[128];
681
682         move(l, lc);
683 #ifdef DEBUG
684                 while (--w >= 0)
685                         addch('*');
686                 return;
687 #endif
688         if (nz && f == 0.0) {
689                 while (--w >= 0)
690                         addch(' ');
691                 return;
692         }
693         snr = snprintf(b, sizeof(b), "%*.*f", w, d, f);
694         if (snr != w)
695                 snr = snprintf(b, sizeof(b), "%*.0f", w, f);
696         if (snr != w)
697                 snr = snprintf(b, sizeof(b), "%*.0fk", w - 1, f / 1000);
698         if (snr != w)
699                 snr = snprintf(b, sizeof(b), "%*.0fM", w - 1, f / 1000000);
700         if (snr != w) {
701                 while (--w >= 0)
702                         addch('*');
703                 return;
704         }
705         addstr(b);
706 }
707
708 void
709 putlongdouble(long double f, int l, int lc, int w, int d, int nz)
710 {
711         int snr;
712         char b[128];
713
714         move(l, lc);
715 #ifdef DEBUG
716                 while (--w >= 0)
717                         addch('*');
718                 return;
719 #endif
720         if (nz && f == 0.0) {
721                 while (--w >= 0)
722                         addch(' ');
723                 return;
724         }
725         snr = snprintf(b, sizeof(b), "%*.*Lf", w, d, f);
726         if (snr != w)
727                 snr = snprintf(b, sizeof(b), "%*.0Lf", w, f);
728         if (snr != w)
729                 snr = snprintf(b, sizeof(b), "%*.0Lfk", w - 1, f / 1000);
730         if (snr != w)
731                 snr = snprintf(b, sizeof(b), "%*.0LfM", w - 1, f / 1000000);
732         if (snr != w) {
733                 while (--w >= 0)
734                         addch('*');
735                 return;
736         }
737         addstr(b);
738 }
739
740 static void
741 getinfo(struct Info *ls)
742 {
743         struct devinfo *tmp_dinfo;
744         size_t size;
745         int mib[2];
746
747         GETSYSCTL("kern.cp_time", ls->time);
748         GETSYSCTL("kern.cp_time", cur_dev.cp_time);
749         GETSYSCTL("vm.stats.sys.v_swtch", ls->v_swtch);
750         GETSYSCTL("vm.stats.sys.v_trap", ls->v_trap);
751         GETSYSCTL("vm.stats.sys.v_syscall", ls->v_syscall);
752         GETSYSCTL("vm.stats.sys.v_intr", ls->v_intr);
753         GETSYSCTL("vm.stats.sys.v_soft", ls->v_soft);
754         GETSYSCTL("vm.stats.vm.v_vm_faults", ls->v_vm_faults);
755         GETSYSCTL("vm.stats.vm.v_io_faults", ls->v_io_faults);
756         GETSYSCTL("vm.stats.vm.v_cow_faults", ls->v_cow_faults);
757         GETSYSCTL("vm.stats.vm.v_zfod", ls->v_zfod);
758         GETSYSCTL("vm.stats.vm.v_ozfod", ls->v_ozfod);
759         GETSYSCTL("vm.stats.vm.v_swapin", ls->v_swapin);
760         GETSYSCTL("vm.stats.vm.v_swapout", ls->v_swapout);
761         GETSYSCTL("vm.stats.vm.v_swappgsin", ls->v_swappgsin);
762         GETSYSCTL("vm.stats.vm.v_swappgsout", ls->v_swappgsout);
763         GETSYSCTL("vm.stats.vm.v_vnodein", ls->v_vnodein);
764         GETSYSCTL("vm.stats.vm.v_vnodeout", ls->v_vnodeout);
765         GETSYSCTL("vm.stats.vm.v_vnodepgsin", ls->v_vnodepgsin);
766         GETSYSCTL("vm.stats.vm.v_vnodepgsout", ls->v_vnodepgsout);
767         GETSYSCTL("vm.stats.vm.v_intrans", ls->v_intrans);
768         GETSYSCTL("vm.stats.vm.v_reactivated", ls->v_reactivated);
769         GETSYSCTL("vm.stats.vm.v_pdwakeups", ls->v_pdwakeups);
770         GETSYSCTL("vm.stats.vm.v_pdpages", ls->v_pdpages);
771         GETSYSCTL("vm.stats.vm.v_dfree", ls->v_dfree);
772         GETSYSCTL("vm.stats.vm.v_pfree", ls->v_pfree);
773         GETSYSCTL("vm.stats.vm.v_tfree", ls->v_tfree);
774         GETSYSCTL("vm.stats.vm.v_free_count", ls->v_free_count);
775         GETSYSCTL("vm.stats.vm.v_wire_count", ls->v_wire_count);
776         GETSYSCTL("vm.stats.vm.v_active_count", ls->v_active_count);
777         GETSYSCTL("vm.stats.vm.v_inactive_count", ls->v_inactive_count);
778         GETSYSCTL("vm.stats.vm.v_laundry_count", ls->v_laundry_count);
779         GETSYSCTL("vfs.bufspace", ls->bufspace);
780         GETSYSCTL("kern.maxvnodes", ls->maxvnodes);
781         GETSYSCTL("vfs.numvnodes", ls->numvnodes);
782         GETSYSCTL("vfs.freevnodes", ls->freevnodes);
783         GETSYSCTL("vfs.cache.nchstats", ls->nchstats);
784         GETSYSCTL("vfs.numdirtybuffers", ls->numdirtybuffers);
785         GETSYSCTL("vm.kmem_map_size", ls->v_kmem_map_size);
786         getsysctl("hw.intrcnt", ls->intrcnt, nintr * sizeof(u_long));
787
788         size = sizeof(ls->Total);
789         mib[0] = CTL_VM;
790         mib[1] = VM_TOTAL;
791         if (sysctl(mib, 2, &ls->Total, &size, NULL, 0) < 0) {
792                 error("Can't get kernel info: %s\n", strerror(errno));
793                 bzero(&ls->Total, sizeof(ls->Total));
794         }
795         size = sizeof(ncpu);
796         if (sysctlbyname("hw.ncpu", &ncpu, &size, NULL, 0) < 0 ||
797             size != sizeof(ncpu))
798                 ncpu = 1;
799
800         tmp_dinfo = last_dev.dinfo;
801         last_dev.dinfo = cur_dev.dinfo;
802         cur_dev.dinfo = tmp_dinfo;
803
804         last_dev.snap_time = cur_dev.snap_time;
805         dsgetinfo(&cur_dev);
806 }
807
808 static void
809 allocinfo(struct Info *ls)
810 {
811
812         ls->intrcnt = (long *) calloc(nintr, sizeof(long));
813         if (ls->intrcnt == NULL)
814                 errx(2, "out of memory");
815 }
816
817 static void
818 copyinfo(struct Info *from, struct Info *to)
819 {
820         long *intrcnt;
821
822         /*
823          * time, wds, seek, and xfer are malloc'd so we have to
824          * save the pointers before the structure copy and then
825          * copy by hand.
826          */
827         intrcnt = to->intrcnt;
828         *to = *from;
829
830         bcopy(from->intrcnt, to->intrcnt = intrcnt, nintr * sizeof (int));
831 }