xref: /openbsd-src/usr.bin/systat/vmstat.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: vmstat.c,v 1.81 2016/08/24 03:13:45 guenther Exp $	*/
2 /*	$NetBSD: vmstat.c,v 1.5 1996/05/10 23:16:40 thorpej Exp $	*/
3 
4 /*-
5  * Copyright (c) 1983, 1989, 1992, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  */
32 
33 /*
34  * Cursed vmstat -- from Robert Elz.
35  */
36 
37 #include <sys/param.h>	/* MAXCOMLEN */
38 #include <sys/types.h>
39 #include <sys/namei.h>
40 #include <sys/proc.h>
41 #include <sys/sched.h>
42 #include <sys/stat.h>
43 #include <sys/sysctl.h>
44 #include <sys/time.h>
45 #include <sys/vmmeter.h>
46 
47 #include <ctype.h>
48 #include <errno.h>
49 #include <err.h>
50 #include <paths.h>
51 #include <signal.h>
52 #include <stdlib.h>
53 #include <string.h>
54 #include <unistd.h>
55 
56 #include "systat.h"
57 #include "dkstats.h"
58 
59 #define MAXIMUM(a, b)	(((a) > (b)) ? (a) : (b))
60 
61 static struct Info {
62 	long	time[CPUSTATES];
63 	struct	uvmexp uvmexp;
64 	struct	vmtotal Total;
65 	struct	nchstats nchstats;
66 	long	nchcount;
67 	uint64_t *intrcnt;
68 } s, s1, s2, s3, z;
69 
70 extern struct _disk	cur;
71 
72 #define	cnt s.Cnt
73 #define oldcnt s1.Cnt
74 #define	total s.Total
75 #define	nchtotal s.nchstats
76 #define	oldnchtotal s1.nchstats
77 
78 static	enum state { BOOT, TIME, RUN } state = TIME;
79 
80 static void allocinfo(struct Info *);
81 static void copyinfo(struct Info *, struct Info *);
82 static float cputime(int);
83 static void dinfo(int, int);
84 static void getinfo(struct Info *);
85 void putint(int, int, int, int);
86 void putintmk(int, int, int, int);
87 void putuint64(u_int64_t, int, int, int);
88 void putfloat(double, int, int, int, int, int);
89 int ucount(void);
90 
91 void print_vm(void);
92 int read_vm(void);
93 int select_vm(void);
94 int vm_keyboard_callback(int);
95 
96 static	time_t t;
97 static	double etime;
98 static	float hertz;
99 static	int nintr;
100 static	long *intrloc;
101 static	char **intrname;
102 static	int nextintsrow;
103 
104 WINDOW *
105 openkre(void)
106 {
107 	return (subwin(stdscr, LINES-1-1, 0, 1, 0));
108 }
109 
110 void
111 closekre(WINDOW *w)
112 {
113 
114 	if (w == NULL)
115 		return;
116 	wclear(w);
117 	wrefresh(w);
118 	delwin(w);
119 }
120 
121 /*
122  * These constants define where the major pieces are laid out
123  */
124 #define STATROW		 0	/* uses 1 row and 68 cols */
125 #define STATCOL		 2
126 #define MEMROW		 2	/* uses 4 rows and 34 cols */
127 #define MEMCOL		 0
128 #define PAGEROW		 2	/* uses 4 rows and 26 cols */
129 #define PAGECOL		37
130 #define INTSROW		 2	/* uses all rows to bottom and 17 cols */
131 #define INTSCOL		63
132 #define PROCSROW	 7	/* uses 2 rows and 20 cols */
133 #define PROCSCOL	 0
134 #define GENSTATROW	 7	/* uses 2 rows and 35 cols */
135 #define GENSTATCOL	16
136 #define VMSTATROW	 7	/* uses 18 rows and 12 cols */
137 #define VMSTATCOL	48
138 #define GRAPHROW	10	/* uses 3 rows and 51 cols */
139 #define GRAPHCOL	 0
140 #define NAMEIROW	14	/* uses 3 rows and 49 cols */
141 #define NAMEICOL	 0
142 #define DISKROW		18	/* uses 5 rows and 50 cols (for 9 drives) */
143 #define DISKCOL		 0
144 
145 #define	DRIVESPACE	45	/* max space for drives */
146 
147 
148 field_def *view_vm_0[] = {
149 	NULL
150 };
151 
152 /* Define view managers */
153 struct view_manager vmstat_mgr = {
154 	"VMstat", select_vm, read_vm, NULL, print_header,
155 	print_vm, vm_keyboard_callback, NULL, NULL
156 };
157 
158 field_view views_vm[] = {
159 	{view_vm_0, "vmstat", '7', &vmstat_mgr},
160 	{NULL, NULL, 0, NULL}
161 };
162 
163 int
164 initvmstat(void)
165 {
166 	field_view *v;
167 	int mib[4], i;
168 	size_t size;
169 
170 	hertz = stathz;
171 	if (!dkinit(1))
172 		return(0);
173 
174 	mib[0] = CTL_KERN;
175 	mib[1] = KERN_INTRCNT;
176 	mib[2] = KERN_INTRCNT_NUM;
177 	size = sizeof(nintr);
178 	if (sysctl(mib, 3, &nintr, &size, NULL, 0) < 0)
179 		return (-1);
180 
181 	intrloc = calloc(nintr, sizeof(long));
182 	intrname = calloc(nintr, sizeof(char *));
183 
184 	for (i = 0; i < nintr; i++) {
185 		char name[128];
186 
187 		mib[0] = CTL_KERN;
188 		mib[1] = KERN_INTRCNT;
189 		mib[2] = KERN_INTRCNT_NAME;
190 		mib[3] = i;
191 		size = sizeof(name);
192 		if (sysctl(mib, 4, name, &size, NULL, 0) < 0)
193 			return (-1);
194 
195 		intrname[i] = strdup(name);
196 		if (intrname[i] == NULL)
197 			return (-1);
198 	}
199 
200 	nextintsrow = INTSROW + 2;
201 	allocinfo(&s);
202 	allocinfo(&s1);
203 	allocinfo(&s2);
204 	allocinfo(&s3);
205 	allocinfo(&z);
206 
207 	getinfo(&s2);
208 	copyinfo(&z, &s1);
209 
210 	for (v = views_vm; v->name != NULL; v++)
211 		add_view(v);
212 
213 	return(1);
214 }
215 
216 void
217 fetchkre(void)
218 {
219 	getinfo(&s3);
220 }
221 
222 void
223 labelkre(void)
224 {
225 	int i, j, l;
226 
227 	mvprintw(MEMROW, MEMCOL,     "            memory totals (in KB)");
228 	mvprintw(MEMROW + 1, MEMCOL, "           real   virtual     free");
229 	mvprintw(MEMROW + 2, MEMCOL, "Active");
230 	mvprintw(MEMROW + 3, MEMCOL, "All");
231 
232 	mvprintw(PAGEROW, PAGECOL, "        PAGING   SWAPPING ");
233 	mvprintw(PAGEROW + 1, PAGECOL, "        in  out   in  out ");
234 	mvprintw(PAGEROW + 2, PAGECOL, "ops");
235 	mvprintw(PAGEROW + 3, PAGECOL, "pages");
236 
237 	mvprintw(INTSROW, INTSCOL + 3, " Interrupts");
238 	mvprintw(INTSROW + 1, INTSCOL + 9, "total");
239 
240 	mvprintw(LINES - 3, INTSCOL + 9, "IPKTS");
241 	mvprintw(LINES - 2, INTSCOL + 9, "OPKTS");
242 
243 	mvprintw(VMSTATROW + 0, VMSTATCOL + 10, "forks");
244 	mvprintw(VMSTATROW + 1, VMSTATCOL + 10, "fkppw");
245 	mvprintw(VMSTATROW + 2, VMSTATCOL + 10, "fksvm");
246 	mvprintw(VMSTATROW + 3, VMSTATCOL + 10, "pwait");
247 	mvprintw(VMSTATROW + 4, VMSTATCOL + 10, "relck");
248 	mvprintw(VMSTATROW + 5, VMSTATCOL + 10, "rlkok");
249 	mvprintw(VMSTATROW + 6, VMSTATCOL + 10, "noram");
250 	mvprintw(VMSTATROW + 7, VMSTATCOL + 10, "ndcpy");
251 	mvprintw(VMSTATROW + 8, VMSTATCOL + 10, "fltcp");
252 	mvprintw(VMSTATROW + 9, VMSTATCOL + 10, "zfod");
253 	mvprintw(VMSTATROW + 10, VMSTATCOL + 10, "cow");
254 	mvprintw(VMSTATROW + 11, VMSTATCOL + 10, "fmin");
255 	mvprintw(VMSTATROW + 12, VMSTATCOL + 10, "ftarg");
256 	mvprintw(VMSTATROW + 13, VMSTATCOL + 10, "itarg");
257 	mvprintw(VMSTATROW + 14, VMSTATCOL + 10, "wired");
258 	mvprintw(VMSTATROW + 15, VMSTATCOL + 10, "pdfre");
259 	if (LINES - 1 > VMSTATROW + 16)
260 		mvprintw(VMSTATROW + 16, VMSTATCOL + 10, "pdscn");
261 	if (LINES - 1 > VMSTATROW + 17)
262 		mvprintw(VMSTATROW + 17, VMSTATCOL + 10, "pzidle");
263 	if (LINES - 1 > VMSTATROW + 18)
264 		mvprintw(VMSTATROW + 18, VMSTATCOL + 10, "kmapent");
265 
266 	mvprintw(GENSTATROW, GENSTATCOL, "   Csw   Trp   Sys   Int   Sof  Flt");
267 
268 	mvprintw(GRAPHROW, GRAPHCOL,
269 	    "    . %%Int    . %%Sys    . %%Usr    . %%Nic    . %%Idle");
270 	mvprintw(PROCSROW, PROCSCOL, "Proc:r  d  s  w");
271 	mvprintw(GRAPHROW + 1, GRAPHCOL,
272 	    "|    |    |    |    |    |    |    |    |    |    |");
273 
274 	mvprintw(NAMEIROW, NAMEICOL,
275 	    "Namei         Sys-cache    Proc-cache    No-cache");
276 	mvprintw(NAMEIROW + 1, NAMEICOL,
277 	    "    Calls     hits    %%    hits     %%    miss   %%");
278 	mvprintw(DISKROW, DISKCOL, "Disks");
279 	mvprintw(DISKROW + 1, DISKCOL, "seeks");
280 	mvprintw(DISKROW + 2, DISKCOL, "xfers");
281 	mvprintw(DISKROW + 3, DISKCOL, "speed");
282 	mvprintw(DISKROW + 4, DISKCOL, "  sec");
283 	for (i = 0, j = 0; i < cur.dk_ndrive && j < DRIVESPACE; i++)
284 		if (cur.dk_select[i] && (j + strlen(dr_name[i])) < DRIVESPACE) {
285 			l = MAXIMUM(5, strlen(dr_name[i]));
286 			mvprintw(DISKROW, DISKCOL + 5 + j,
287 			    " %*s", l, dr_name[i]);
288 			j += 1 + l;
289 		}
290 	for (i = 0; i < nintr; i++) {
291 		if (intrloc[i] == 0)
292 			continue;
293 		mvprintw(intrloc[i], INTSCOL + 9, "%-8.8s", intrname[i]);
294 	}
295 }
296 
297 #define X(fld)	{s.fld[i]; s.fld[i]-=s1.fld[i];}
298 #define Y(fld)	{s.fld; s.fld -= s1.fld;}
299 #define Z(fld)	{s.nchstats.fld; s.nchstats.fld -= s1.nchstats.fld;}
300 #define PUTRATE(fld, l, c, w) \
301 	do { \
302 		Y(fld); \
303 		putint((int)((float)s.fld/etime + 0.5), l, c, w); \
304 	} while (0)
305 #define MAXFAIL 5
306 
307 static	char cpuchar[CPUSTATES] = { '|', '=', '>', '-', ' ' };
308 static	char cpuorder[CPUSTATES] = { CP_INTR, CP_SYS, CP_USER, CP_NICE, CP_IDLE };
309 
310 void
311 showkre(void)
312 {
313 	float f1, f2;
314 	int psiz;
315 	u_int64_t inttotal, intcnt;
316 	int i, l, c;
317 	static int failcnt = 0, first_run = 0;
318 
319 	if (state == TIME) {
320 		if (!first_run) {
321 			first_run = 1;
322 			return;
323 		}
324 	}
325 	etime = 0;
326 	for (i = 0; i < CPUSTATES; i++) {
327 		X(time);
328 		etime += s.time[i];
329 	}
330 	if (etime < 5.0) {	/* < 5 ticks - ignore this trash */
331 		if (failcnt++ >= MAXFAIL) {
332 			error("The alternate system clock has died!");
333 			failcnt = 0;
334 		}
335 		return;
336 	}
337 	failcnt = 0;
338 	etime /= hertz;
339 	inttotal = 0;
340 	for (i = 0; i < nintr; i++) {
341 		if (s.intrcnt[i] == 0)
342 			continue;
343 		if (intrloc[i] == 0) {
344 			if (nextintsrow == LINES)
345 				continue;
346 			intrloc[i] = nextintsrow++;
347 			mvprintw(intrloc[i], INTSCOL + 9, "%-8.8s",
348 			    intrname[i]);
349 		}
350 		t = intcnt = s.intrcnt[i];
351 		s.intrcnt[i] -= s1.intrcnt[i];
352 		intcnt = (u_int64_t)((float)s.intrcnt[i]/etime + 0.5);
353 		inttotal += intcnt;
354 		putuint64(intcnt, intrloc[i], INTSCOL, 8);
355 	}
356 	putuint64(inttotal, INTSROW + 1, INTSCOL, 8);
357 	Z(ncs_goodhits); Z(ncs_badhits); Z(ncs_miss);
358 	Z(ncs_long); Z(ncs_pass2); Z(ncs_2passes);
359 	s.nchcount = nchtotal.ncs_goodhits + nchtotal.ncs_badhits +
360 	    nchtotal.ncs_miss + nchtotal.ncs_long;
361 
362 	putint(sum.ifc_ip, LINES - 3, INTSCOL, 8);
363 	putint(sum.ifc_op, LINES - 2, INTSCOL, 8);
364 
365 	psiz = 0;
366 	f2 = 0.0;
367 
368 	for (c = 0; c < CPUSTATES; c++) {
369 		i = cpuorder[c];
370 		f1 = cputime(i);
371 		f2 += f1;
372 		l = (int) ((f2 + 1.0) / 2.0) - psiz;
373 		putfloat(f1, GRAPHROW, GRAPHCOL + 1 + (10 * c), 5, 1, 0);
374 		move(GRAPHROW + 2, psiz);
375 		psiz += l;
376 		while (l-- > 0)
377 			addch(cpuchar[c]);
378 	}
379 
380 #define pgtokb(pg)	((pg) * (s.uvmexp.pagesize / 1024))
381 
382 	putint(pgtokb(s.uvmexp.active), MEMROW + 2, MEMCOL + 7, 8);
383 	putint(pgtokb(s.uvmexp.active + s.uvmexp.swpginuse),    /* XXX */
384 	    MEMROW + 2, MEMCOL + 17, 8);
385 	putint(pgtokb(s.uvmexp.npages - s.uvmexp.free), MEMROW + 3, MEMCOL + 7, 8);
386 	putint(pgtokb(s.uvmexp.npages - s.uvmexp.free + s.uvmexp.swpginuse),
387 	    MEMROW + 3, MEMCOL + 17, 8);
388 	putint(pgtokb(s.uvmexp.free), MEMROW + 2, MEMCOL + 26, 8);
389 	putint(pgtokb(s.uvmexp.free + s.uvmexp.swpages - s.uvmexp.swpginuse),
390 	    MEMROW + 3, MEMCOL + 26, 8);
391 	putint(total.t_rq - 1, PROCSROW + 1, PROCSCOL + 3, 3);
392 
393 	putint(total.t_dw, PROCSROW + 1, PROCSCOL + 6, 3);
394 	putint(total.t_sl, PROCSROW + 1, PROCSCOL + 9, 3);
395 	putint(total.t_sw, PROCSROW + 1, PROCSCOL + 12, 3);
396 	PUTRATE(uvmexp.forks, VMSTATROW + 0, VMSTATCOL + 3, 6);
397 	PUTRATE(uvmexp.forks_ppwait, VMSTATROW + 1, VMSTATCOL + 3, 6);
398 	PUTRATE(uvmexp.forks_sharevm, VMSTATROW + 2, VMSTATCOL + 3, 6);
399 	PUTRATE(uvmexp.fltpgwait, VMSTATROW + 3, VMSTATCOL + 4, 5);
400 	PUTRATE(uvmexp.fltrelck, VMSTATROW + 4, VMSTATCOL + 3, 6);
401 	PUTRATE(uvmexp.fltrelckok, VMSTATROW + 5, VMSTATCOL + 3, 6);
402 	PUTRATE(uvmexp.fltnoram, VMSTATROW + 6, VMSTATCOL + 3, 6);
403 	PUTRATE(uvmexp.fltamcopy, VMSTATROW + 7, VMSTATCOL + 3, 6);
404 	PUTRATE(uvmexp.flt_prcopy, VMSTATROW + 8, VMSTATCOL + 3, 6);
405 	PUTRATE(uvmexp.flt_przero, VMSTATROW + 9, VMSTATCOL + 3, 6);
406 	PUTRATE(uvmexp.flt_acow, VMSTATROW + 10, VMSTATCOL, 9);
407 	putint(s.uvmexp.freemin, VMSTATROW + 11, VMSTATCOL, 9);
408 	putint(s.uvmexp.freetarg, VMSTATROW + 12, VMSTATCOL, 9);
409 	putint(s.uvmexp.inactarg, VMSTATROW + 13, VMSTATCOL, 9);
410 	putint(s.uvmexp.wired, VMSTATROW + 14, VMSTATCOL, 9);
411 	PUTRATE(uvmexp.pdfreed, VMSTATROW + 15, VMSTATCOL, 9);
412 	if (LINES - 1 > VMSTATROW + 16)
413 		PUTRATE(uvmexp.pdscans, VMSTATROW + 16, VMSTATCOL, 9);
414 	if (LINES - 1 > VMSTATROW + 17)
415 		PUTRATE(uvmexp.zeropages, VMSTATROW + 17, VMSTATCOL, 9);
416 	if (LINES - 1 > VMSTATROW + 18)
417 		putint(s.uvmexp.kmapent, VMSTATROW + 18, VMSTATCOL, 9);
418 
419 	PUTRATE(uvmexp.pageins, PAGEROW + 2, PAGECOL + 5, 5);
420 	PUTRATE(uvmexp.pdpageouts, PAGEROW + 2, PAGECOL + 10, 5);
421 	PUTRATE(uvmexp.pgswapin, PAGEROW + 3, PAGECOL + 5, 5);
422 	PUTRATE(uvmexp.pgswapout, PAGEROW + 3, PAGECOL + 10, 5);
423 
424 	PUTRATE(uvmexp.swtch, GENSTATROW + 1, GENSTATCOL, 6);
425 	PUTRATE(uvmexp.traps, GENSTATROW + 1, GENSTATCOL + 6, 6);
426 	PUTRATE(uvmexp.syscalls, GENSTATROW + 1, GENSTATCOL + 12, 6);
427 	PUTRATE(uvmexp.intrs, GENSTATROW + 1, GENSTATCOL + 18, 6);
428 	PUTRATE(uvmexp.softs, GENSTATROW + 1, GENSTATCOL + 24, 6);
429 	PUTRATE(uvmexp.faults, GENSTATROW + 1, GENSTATCOL + 30, 5);
430 	mvprintw(DISKROW, DISKCOL + 5, "                              ");
431 	for (i = 0, c = 0; i < cur.dk_ndrive && c < DRIVESPACE; i++)
432 		if (cur.dk_select[i] && (c + strlen(dr_name[i])) < DRIVESPACE) {
433 			l = MAXIMUM(5, strlen(dr_name[i]));
434 			mvprintw(DISKROW, DISKCOL + 5 + c,
435 			    " %*s", l, dr_name[i]);
436 			c += 1 + l;
437 			dinfo(i, c);
438 		}
439 	/* and pad the DRIVESPACE */
440 	l = DRIVESPACE - c;
441 	for (i = 0; i < 5; i++)
442 		mvprintw(DISKROW + i, DISKCOL + 5 + c, "%*s", l, "");
443 
444 	putint(s.nchcount, NAMEIROW + 2, NAMEICOL, 9);
445 	putint(nchtotal.ncs_goodhits, NAMEIROW + 2, NAMEICOL + 10, 8);
446 #define nz(x)	((x) ? (x) : 1)
447 	putfloat(nchtotal.ncs_goodhits * 100.0 / nz(s.nchcount),
448 	    NAMEIROW + 2, NAMEICOL + 19, 4, 0, 1);
449 	putint(nchtotal.ncs_pass2, NAMEIROW + 2, NAMEICOL + 24, 7);
450 	putfloat(nchtotal.ncs_pass2 * 100.0 / nz(s.nchcount),
451 	    NAMEIROW + 2, NAMEICOL + 33, 4, 0, 1);
452 	putint(nchtotal.ncs_miss + nchtotal.ncs_long - nchtotal.ncs_pass2,
453 	   NAMEIROW + 2, NAMEICOL + 38, 7);
454 	putfloat((nchtotal.ncs_miss + nchtotal.ncs_long - nchtotal.ncs_pass2) *
455 	    100.0 / nz(s.nchcount), NAMEIROW + 2, NAMEICOL + 45, 4, 0, 1);
456 #undef nz
457 
458 }
459 
460 int
461 vm_keyboard_callback(int ch)
462 {
463 	switch(ch) {
464 	case 'r':
465 		copyinfo(&s2, &s1);
466 		state = RUN;
467 		break;
468 	case 'b':
469 		state = BOOT;
470 		copyinfo(&z, &s1);
471 		break;
472 	case 't':
473 		state = TIME;
474 		break;
475 	case 'z':
476 		if (state == RUN)
477 			getinfo(&s1);
478 		break;
479 	}
480 	return (keyboard_callback(ch));
481 }
482 
483 
484 static float
485 cputime(int indx)
486 {
487 	double tm;
488 	int i;
489 
490 	tm = 0;
491 	for (i = 0; i < CPUSTATES; i++)
492 		tm += s.time[i];
493 	if (tm == 0.0)
494 		tm = 1.0;
495 	return (s.time[indx] * 100.0 / tm);
496 }
497 
498 void
499 putint(int n, int l, int c, int w)
500 {
501 	char b[128];
502 
503 	move(l, c);
504 	if (n == 0) {
505 		while (w-- > 0)
506 			addch(' ');
507 		return;
508 	}
509 	snprintf(b, sizeof b, "%*d", w, n);
510 	if (strlen(b) > w) {
511 		while (w-- > 0)
512 			addch('*');
513 		return;
514 	}
515 	addstr(b);
516 }
517 
518 void
519 putintmk(int n, int l, int c, int w)
520 {
521 	char b[128];
522 
523 	move(l, c);
524 	if (n == 0) {
525 		while (w-- > 0)
526 			addch(' ');
527 		return;
528 	}
529 	if (n > 9999 * 1024)
530 		snprintf(b, sizeof b, "%*dG", w - 1, n / 1024 / 1024);
531 	else if (n > 9999)
532 		snprintf(b, sizeof b, "%*dM", w - 1, n / 1024);
533 	else
534 		snprintf(b, sizeof b, "%*dK", w - 1, n);
535 	if (strlen(b) > w) {
536 		while (w-- > 0)
537 			addch('*');
538 		return;
539 	}
540 	addstr(b);
541 }
542 
543 void
544 putuint64(u_int64_t n, int l, int c, int w)
545 {
546 	char b[128];
547 
548 	move(l, c);
549 	if (n == 0) {
550 		while (w-- > 0)
551 			addch(' ');
552 		return;
553 	}
554 	snprintf(b, sizeof b, "%*llu", w, n);
555 	if (strlen(b) > w) {
556 		while (w-- > 0)
557 			addch('*');
558 		return;
559 	}
560 	addstr(b);
561 }
562 
563 void
564 putfloat(double f, int l, int c, int w, int d, int nz)
565 {
566 	char b[128];
567 
568 	move(l, c);
569 	if (nz && f == 0.0) {
570 		while (--w >= 0)
571 			addch(' ');
572 		return;
573 	}
574 	snprintf(b, sizeof b, "%*.*f", w, d, f);
575 	if (strlen(b) > w) {
576 		while (--w >= 0)
577 			addch('*');
578 		return;
579 	}
580 	addstr(b);
581 }
582 
583 static void
584 getinfo(struct Info *si)
585 {
586 	static int cp_time_mib[] = { CTL_KERN, KERN_CPTIME };
587 	static int nchstats_mib[2] = { CTL_KERN, KERN_NCHSTATS };
588 	static int uvmexp_mib[2] = { CTL_VM, VM_UVMEXP };
589 	static int vmtotal_mib[2] = { CTL_VM, VM_METER };
590 	int mib[4], i;
591 	size_t size;
592 
593 	dkreadstats();
594 
595 	for (i = 0; i < nintr; i++) {
596 		mib[0] = CTL_KERN;
597 		mib[1] = KERN_INTRCNT;
598 		mib[2] = KERN_INTRCNT_CNT;
599 		mib[3] = i;
600 		size = sizeof(si->intrcnt[i]);
601 		if (sysctl(mib, 4, &si->intrcnt[i], &size, NULL, 0) < 0) {
602 			si->intrcnt[i] = 0;
603 		}
604 	}
605 
606 	size = sizeof(si->time);
607 	if (sysctl(cp_time_mib, 2, &si->time, &size, NULL, 0) < 0) {
608 		error("Can't get KERN_CPTIME: %s\n", strerror(errno));
609 		memset(&si->time, 0, sizeof(si->time));
610 	}
611 
612 	size = sizeof(si->nchstats);
613 	if (sysctl(nchstats_mib, 2, &si->nchstats, &size, NULL, 0) < 0) {
614 		error("Can't get KERN_NCHSTATS: %s\n", strerror(errno));
615 		memset(&si->nchstats, 0, sizeof(si->nchstats));
616 	}
617 
618 	size = sizeof(si->uvmexp);
619 	if (sysctl(uvmexp_mib, 2, &si->uvmexp, &size, NULL, 0) < 0) {
620 		error("Can't get VM_UVMEXP: %s\n", strerror(errno));
621 		memset(&si->uvmexp, 0, sizeof(si->uvmexp));
622 	}
623 
624 	size = sizeof(si->Total);
625 	if (sysctl(vmtotal_mib, 2, &si->Total, &size, NULL, 0) < 0) {
626 		error("Can't get VM_METER: %s\n", strerror(errno));
627 		memset(&si->Total, 0, sizeof(si->Total));
628 	}
629 }
630 
631 static void
632 allocinfo(struct Info *si)
633 {
634 	memset(si, 0, sizeof(*si));
635 	si->intrcnt = calloc(nintr, sizeof(*si->intrcnt));
636 	if (si->intrcnt == NULL)
637 		errx(2, "out of memory");
638 }
639 
640 static void
641 copyinfo(struct Info *from, struct Info *to)
642 {
643 	uint64_t *intrcnt;
644 
645 	intrcnt = to->intrcnt;
646 	*to = *from;
647 	memcpy(to->intrcnt = intrcnt, from->intrcnt, nintr * sizeof(*intrcnt));
648 }
649 
650 static void
651 dinfo(int dn, int c)
652 {
653 	double words, atime;
654 
655 	c += DISKCOL;
656 
657 	/* time busy in disk activity */
658 	atime = (double)cur.dk_time[dn].tv_sec +
659 	    ((double)cur.dk_time[dn].tv_usec / (double)1000000);
660 
661 	/* # of K transferred */
662 	words = (cur.dk_rbytes[dn] + cur.dk_wbytes[dn]) / 1024.0;
663 
664 	putint((int)((float)cur.dk_seek[dn]/etime+0.5), DISKROW + 1, c, 5);
665 	putint((int)((float)(cur.dk_rxfer[dn] + cur.dk_wxfer[dn])/etime+0.5),
666 	    DISKROW + 2, c, 5);
667 	putintmk((int)(words/etime + 0.5), DISKROW + 3, c, 5);
668 	putfloat(atime/etime, DISKROW + 4, c, 5, 1, 1);
669 }
670 
671 
672 
673 int
674 select_vm(void)
675 {
676 	num_disp = 0;
677 	return (0);
678 }
679 
680 int
681 read_vm(void)
682 {
683 	if (state == TIME)
684 		copyinfo(&s3, &s1);
685 	fetchkre();
686 	fetchifstat();
687 	if (state == TIME)
688 		dkswap();
689 	num_disp = 0;
690 	return 0;
691 }
692 
693 
694 void
695 print_vm(void)
696 {
697 	copyinfo(&s3, &s);
698 	labelkre();
699 	showkre();
700 }
701