xref: /original-bsd/usr.bin/systat/vmstat.c (revision abd50c55)
1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 static char sccsid[] = "@(#)vmstat.c	5.11 (Berkeley) 08/28/89";
9 #endif not lint
10 
11 /*
12  * Cursed vmstat -- from Robert Elz.
13  */
14 
15 #include "systat.h"
16 
17 #include <ctype.h>
18 #include <utmp.h>
19 
20 #include <sys/vm.h>
21 #include <sys/buf.h>
22 #include <sys/stat.h>
23 #include <sys/dir.h>
24 #include <sys/user.h>
25 #include <sys/proc.h>
26 #include <sys/namei.h>
27 
28 #include <machine/pte.h>
29 #include <paths.h>
30 
31 static	int ut;
32 
33 WINDOW *
34 openkre()
35 {
36 
37 	ut = open(_PATH_UTMP, O_RDONLY);
38 	if (ut < 0)
39 		error("No utmp");
40 	return (stdscr);
41 }
42 
43 closekre(w)
44 	WINDOW *w;
45 {
46 
47 	(void) close(ut);
48 	if (w == NULL)
49 		return;
50 	wclear(w);
51 	wrefresh(w);
52 }
53 
54 long	time();
55 float	cputime();
56 struct	utmp utmp;
57 
58 static struct nlist name[] = {
59 	{ "_cp_time" },
60 #define X_CPTIME	0
61 	{ "_rate" },
62 #define X_RATE		1
63 	{ "_total" },
64 #define X_TOTAL		2
65 	{ "_proc" },
66 #define X_PROC		3
67 	{ "_nproc" },
68 #define X_NPROC		4
69 	{ "_sum" },
70 #define X_SUM		5
71 	{ "_dk_busy" },
72 #define	X_DK_BUSY	6
73 	{ "_dk_time" },
74 #define	X_DK_TIME	7
75 	{ "_dk_xfer" },
76 #define	X_DK_XFER	8
77 	{ "_dk_wds" },
78 #define	X_DK_WDS	9
79 	{ "_tk_nin" },
80 #define	X_TK_NIN	10
81 	{ "_tk_nout" },
82 #define	X_TK_NOUT	11
83 	{ "_dk_seek" },
84 #define	X_DK_SEEK	12
85 	{ "_nchstats" },
86 #define	X_NCHSTATS	13
87 	{ "_intrnames" },
88 #define	X_INTRNAMES	14
89 	{ "_eintrnames" },
90 #define	X_EINTRNAMES	15
91 	{ "_intrcnt" },
92 #define	X_INTRCNT	16
93 	{ "_eintrcnt" },
94 #define	X_EINTRCNT	17
95 	{ "" },
96 };
97 
98 static struct Info {
99 	long	time[CPUSTATES];
100 	struct	vmmeter Rate;
101 	struct	vmtotal Total;
102 	struct	vmmeter Sum;
103 	struct	forkstat Forkstat;
104 	long	*dk_time;
105 	long	*dk_wds;
106 	long	*dk_seek;
107 	long	*dk_xfer;
108 	int	dk_busy;
109 	long	tk_nin;
110 	long	tk_nout;
111 	struct	nchstats nchstats;
112 	long	nchcount;
113 	long	*intrcnt;
114 } s, s1, s2, z;
115 
116 #define total s.Total
117 #define sum s.Sum
118 #define sumold s1.Sum
119 #define rate s.Rate
120 #define	nchtotal s.nchstats
121 #define	oldnchtotal s1.nchstats
122 #define oldrate s1.Rate
123 
124 static	char buf[26];
125 static	time_t t;
126 static	double etime;
127 static	float hertz;
128 static	int nintr;
129 static	long *intrloc;
130 static	char **intrname;
131 static	int nextintsrow;
132 
133 static	enum state { BOOT, TIME, RUN } state = TIME;
134 
135 /*
136  * These constants define where the major pieces are laid out
137  */
138 #define PROCSROW	13	/* uses 2 rows and 20 cols */
139 #define PROCSCOL	 0
140 #define NAMEIROW	20	/* uses 3 rows and 38 cols */
141 #define NAMEICOL	 0
142 #define GRAPHROW	16	/* uses 3 rows and 51 cols */
143 #define GRAPHCOL	 0
144 #define GENSTATROW	14	/* uses 9 rows and 11 cols */
145 #define GENSTATCOL	51
146 #define INTSROW		 2	/* uses all rows to bottom and 17 cols */
147 #define INTSCOL		63
148 #define STATROW		 0	/* uses 1 row and 68 cols */
149 #define STATCOL		 2
150 #define PAGEROW		 2	/* uses 11 rows and 26 cols */
151 #define PAGECOL		36
152 #define MEMROW		 2	/* uses 4 rows and 31 cols */
153 #define MEMCOL		 0
154 #define DISKROW		 7	/* uses 5 rows and 35 cols */
155 #define DISKCOL		 0
156 
157 initkre()
158 {
159 	char *intrnamebuf, *cp;
160 	int i;
161 	static int once = 0;
162 
163 	if (name[0].n_type == 0) {
164 		nlist(_PATH_UNIX,name);
165 		if (name[0].n_type == 0) {
166 			error("No namelist");
167 			return(0);
168 		}
169 	}
170 	hertz = phz ? phz : hz;
171 	if (! dkinit())
172 		return(0);
173 	if (dk_ndrive && !once) {
174 #define	allocate(e, t) \
175     s./**/e = (t *)calloc(dk_ndrive, sizeof (t)); \
176     s1./**/e = (t *)calloc(dk_ndrive, sizeof (t)); \
177     s2./**/e = (t *)calloc(dk_ndrive, sizeof (t)); \
178     z./**/e = (t *)calloc(dk_ndrive, sizeof (t));
179 		allocate(dk_time, long);
180 		allocate(dk_wds, long);
181 		allocate(dk_seek, long);
182 		allocate(dk_xfer, long);
183 		once = 1;
184 #undef allocate
185 	}
186 	if (nintr == 0) {
187 		nintr = (name[X_EINTRCNT].n_value -
188 			name[X_INTRCNT].n_value) / sizeof (long);
189 		intrloc = (long *) calloc(nintr, sizeof (long));
190 		intrname = (char **) calloc(nintr, sizeof (long));
191 		intrnamebuf = malloc(name[X_EINTRNAMES].n_value -
192 			name[X_INTRNAMES].n_value);
193 		if (intrnamebuf == 0 || intrname == 0 || intrloc == 0) {
194 			error("Out of memory\n");
195 			if (intrnamebuf)
196 				free(intrnamebuf);
197 			if (intrname)
198 				free(intrname);
199 			if (intrloc)
200 				free(intrloc);
201 			nintr = 0;
202 			return(0);
203 		}
204 		lseek(kmem, (long)name[X_INTRNAMES].n_value, L_SET);
205 		read(kmem, intrnamebuf, name[X_EINTRNAMES].n_value -
206 			name[X_INTRNAMES].n_value);
207 		for (cp = intrnamebuf, i = 0; i < nintr; i++) {
208 			intrname[i] = cp;
209 			cp += strlen(cp) + 1;
210 		}
211 		nextintsrow = INTSROW + 2;
212 		allocinfo(&s);
213 		allocinfo(&s1);
214 		allocinfo(&s2);
215 		allocinfo(&z);
216 	}
217 	getinfo(&s2, RUN);
218 	copyinfo(&s2, &s1);
219 	return(1);
220 }
221 
222 fetchkre()
223 {
224 	time_t now;
225 
226 	time(&now);
227 	strcpy(buf, ctime(&now));
228 	buf[16] = '\0';
229 	getinfo(&s, state);
230 }
231 
232 #define	MAXDRIVES	6		/* max # to display */
233 
234 labelkre()
235 {
236 	register i, j;
237 
238 	clear();
239 	mvprintw(STATROW, STATCOL + 4, "users    Load");
240 	mvprintw(MEMROW, MEMCOL, "Mem     REAL     VIRTUAL");
241 	mvprintw(MEMROW + 1, MEMCOL, "      Tot Text   Tot Text");
242 	mvprintw(MEMROW + 2, MEMCOL, "Act");
243 	mvprintw(MEMROW + 3, MEMCOL, "All");
244 
245 	mvprintw(MEMROW + 1, MEMCOL + 28, "Free");
246 
247 	mvprintw(PAGEROW, PAGECOL, "        PAGING    SWAPING ");
248 	mvprintw(PAGEROW + 1, PAGECOL, "        in  out   in  out ");
249 	mvprintw(PAGEROW + 2, PAGECOL, "count");
250 	mvprintw(PAGEROW + 3, PAGECOL, "pages");
251 
252 	mvprintw(INTSROW, INTSCOL, " Interrupts");
253 	mvprintw(INTSROW + 1, INTSCOL + 9, "total");
254 
255 	mvprintw(GENSTATROW, GENSTATCOL + 8, "Csw");
256 	mvprintw(GENSTATROW + 1, GENSTATCOL + 8, "Trp");
257 	mvprintw(GENSTATROW + 2, GENSTATCOL + 8, "Sys");
258 	mvprintw(GENSTATROW + 3, GENSTATCOL + 8, "Int");
259 	mvprintw(GENSTATROW + 4, GENSTATCOL + 8, "Pdm");
260 	mvprintw(GENSTATROW + 5, GENSTATCOL + 8, "Sof");
261 	mvprintw(GENSTATROW + 6, GENSTATCOL + 8, "Flt");
262 	mvprintw(GENSTATROW + 7, GENSTATCOL + 8, "Scn");
263 	mvprintw(GENSTATROW + 8, GENSTATCOL + 8, "Rev");
264 
265 	mvprintw(PAGEROW + 5, PAGECOL, "Rec It F/S F/F RFL Fre SFr");
266 
267 	mvprintw(PAGEROW + 8, PAGECOL + 9, " zf");
268 	mvprintw(PAGEROW + 9, PAGECOL + 9, "nzf");
269 	mvprintw(PAGEROW + 10, PAGECOL + 9, "%%zf");
270 	mvprintw(PAGEROW + 8, PAGECOL + 23, " xf");
271 	mvprintw(PAGEROW + 9, PAGECOL + 23, "nxf");
272 	mvprintw(PAGEROW + 10, PAGECOL + 23, "%%xf");
273 
274 	mvprintw(GRAPHROW, GRAPHCOL,
275 		"    . %% Sys    . %% User    . %% Nice    . %% Idle");
276 	mvprintw(PROCSROW, PROCSCOL, "Procs  r  p  d  s  w");
277 	mvprintw(GRAPHROW + 1, GRAPHCOL,
278 		"|    |    |    |    |    |    |    |    |    |    |");
279 
280 	mvprintw(NAMEIROW, NAMEICOL, "Namei         Sys-cache     Proc-cache");
281 	mvprintw(NAMEIROW + 1, NAMEICOL,
282 		"    Calls     hits    %%     hits     %%");
283 	mvprintw(DISKROW, DISKCOL, "Discs");
284 	mvprintw(DISKROW + 1, DISKCOL, "seeks");
285 	mvprintw(DISKROW + 2, DISKCOL, "xfers");
286 	mvprintw(DISKROW + 3, DISKCOL, " blks");
287 	mvprintw(DISKROW + 4, DISKCOL, " msps");
288 	j = 0;
289 	for (i = 0; i < dk_ndrive && j < MAXDRIVES; i++)
290 		if (dk_select[i]) {
291 			mvprintw(DISKROW, DISKCOL + 5 + 5 * j,
292 				"  %3.3s", dr_name[j]);
293 			j++;
294 		}
295 	for (i = 0; i < nintr; i++) {
296 		if (intrloc[i] == 0)
297 			continue;
298 		mvprintw(intrloc[i], INTSCOL + 9, "%-8.8s", intrname[i]);
299 	}
300 }
301 
302 #define X(fld)	{t=s.fld[i]; s.fld[i]-=s1.fld[i]; if(state==TIME) s1.fld[i]=t;}
303 #define Y(fld)	{t = s.fld; s.fld -= s1.fld; if(state == TIME) s1.fld = t;}
304 #define Z(fld)	{t = s.nchstats.fld; s.nchstats.fld -= s1.nchstats.fld; \
305 	if(state == TIME) s1.nchstats.fld = t;}
306 #define MAXFAIL 5
307 
308 static	char cpuchar[CPUSTATES] = { '=' , '>', '-', ' ' };
309 static	char cpuorder[CPUSTATES] = { CP_SYS, CP_USER, CP_NICE, CP_IDLE };
310 
311 showkre()
312 {
313 	float f1, f2;
314 	int psiz, inttotal;
315 	int i, l, c;
316 	static int failcnt = 0;
317 
318 	for (i = 0; i < dk_ndrive; i++) {
319 		X(dk_xfer); X(dk_seek); X(dk_wds); X(dk_time);
320 	}
321 	Y(tk_nin); Y(tk_nout);
322 	etime = 0;
323 	for(i = 0; i < CPUSTATES; i++) {
324 		X(time);
325 		etime += s.time[i];
326 	}
327 	if (etime < 5.0) {	/* < 5 ticks - ignore this trash */
328 		if (failcnt++ >= MAXFAIL) {
329 			clear();
330 			mvprintw(2, 10, "The alternate system clock has died!");
331 			mvprintw(3, 10, "Reverting to ``pigs'' display.");
332 			move(CMDLINE, 0);
333 			refresh();
334 			failcnt = 0;
335 			sleep(5);
336 			command("pigs");
337 		}
338 		return;
339 	}
340 	failcnt = 0;
341 	etime /= hertz;
342 	inttotal = 0;
343 	for (i = 0; i < nintr; i++) {
344 		if (s.intrcnt[i] == 0)
345 			continue;
346 		if (intrloc[i] == 0) {
347 			if (nextintsrow == LINES)
348 				continue;
349 			intrloc[i] = nextintsrow++;
350 			mvprintw(intrloc[i], INTSCOL + 9, "%-8.8s",
351 				intrname[i]);
352 		}
353 		X(intrcnt);
354 		l = (int)((float)s.intrcnt[i]/etime + 0.5);
355 		inttotal += l;
356 		putint(l, intrloc[i], INTSCOL, 8);
357 	}
358 	putint(inttotal, INTSROW + 1, INTSCOL, 8);
359 	Z(ncs_goodhits); Z(ncs_badhits); Z(ncs_miss);
360 	Z(ncs_long); Z(ncs_pass2); Z(ncs_2passes);
361 	s.nchcount = nchtotal.ncs_goodhits + nchtotal.ncs_badhits +
362 	    nchtotal.ncs_miss + nchtotal.ncs_long;
363 	if (state == TIME)
364 		s1.nchcount = s.nchcount;
365 
366 	psiz = 0;
367 	f2 = 0.0;
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 		if (c == 0)
374 			putfloat(f1, GRAPHROW, GRAPHCOL + 1, 5, 1, 0);
375 		else
376 			putfloat(f1, GRAPHROW, GRAPHCOL + 12 * c,
377 				5, 1, 0);
378 		move(GRAPHROW + 2, psiz);
379 		psiz += l;
380 		while (l-- > 0)
381 			addch(cpuchar[c]);
382 	}
383 
384 	putint(ucount(), STATROW, STATCOL, 3);
385 	putfloat(avenrun[0], STATROW, STATCOL + 17, 6, 2, 0);
386 	putfloat(avenrun[1], STATROW, STATCOL + 23, 6, 2, 0);
387 	putfloat(avenrun[2], STATROW, STATCOL + 29, 6, 2, 0);
388 	mvaddstr(STATROW, STATCOL + 53, buf);
389 #define pgtokb(pg)	((pg) * NBPG / 1024)
390 	putint(pgtokb(total.t_arm), MEMROW + 2, MEMCOL + 4, 5);
391 	putint(pgtokb(total.t_armtxt), MEMROW + 2, MEMCOL + 9, 5);
392 	putint(pgtokb(total.t_avm), MEMROW + 2, MEMCOL + 14, 6);
393 	putint(pgtokb(total.t_avmtxt), MEMROW + 2, MEMCOL + 20, 5);
394 	putint(pgtokb(total.t_rm), MEMROW + 3, MEMCOL + 4, 5);
395 	putint(pgtokb(total.t_rmtxt), MEMROW + 3, MEMCOL + 9, 5);
396 	putint(pgtokb(total.t_vm), MEMROW + 3, MEMCOL + 14, 6);
397 	putint(pgtokb(total.t_vmtxt), MEMROW + 3, MEMCOL + 20, 5);
398 	putint(pgtokb(total.t_free), MEMROW + 2, MEMCOL + 27, 5);
399 	putint(total.t_rq, PROCSROW + 1, PROCSCOL + 5, 3);
400 	putint(total.t_pw, PROCSROW + 1, PROCSCOL + 8, 3);
401 	putint(total.t_dw, PROCSROW + 1, PROCSCOL + 11, 3);
402 	putint(total.t_sl, PROCSROW + 1, PROCSCOL + 14, 3);
403 	putint(total.t_sw, PROCSROW + 1, PROCSCOL + 17, 3);
404 	putrate(rate.v_swtch, oldrate.v_swtch,
405 		GENSTATROW, GENSTATCOL, 7);
406 	putrate(rate.v_trap, oldrate.v_trap,
407 		GENSTATROW + 1, GENSTATCOL, 7);
408 	putrate(rate.v_syscall, oldrate.v_syscall,
409 		GENSTATROW + 2, GENSTATCOL, 7);
410 	putrate(rate.v_intr, oldrate.v_intr,
411 		GENSTATROW + 3, GENSTATCOL, 7);
412 	putrate(rate.v_pdma, oldrate.v_pdma,
413 		GENSTATROW + 4, GENSTATCOL, 7);
414 	putrate(rate.v_soft, oldrate.v_soft,
415 		GENSTATROW + 5, GENSTATCOL, 7);
416 	putrate(rate.v_faults, oldrate.v_faults,
417 		GENSTATROW + 6, GENSTATCOL, 7);
418 	putrate(rate.v_scan, oldrate.v_scan,
419 		GENSTATROW + 7, GENSTATCOL, 7);
420 	putrate(rate.v_rev, oldrate.v_rev,
421 		GENSTATROW + 8, GENSTATCOL, 7);
422 	putrate(rate.v_pgin, oldrate.v_pgin, PAGEROW + 2,
423 		PAGECOL + 5, 5);
424 	putrate(rate.v_pgout, oldrate.v_pgout, PAGEROW + 2,
425 		PAGECOL + 10, 5);
426 	putrate(rate.v_swpin, oldrate.v_swpin, PAGEROW + 2,
427 		PAGECOL + 15, 5);
428 	putrate(rate.v_swpout, oldrate.v_swpout, PAGEROW + 2,
429 		PAGECOL + 20, 5);
430 	putrate(rate.v_pgpgin, oldrate.v_pgpgin, PAGEROW + 3,
431 		PAGECOL + 5, 5);
432 	putrate(rate.v_pgpgout, oldrate.v_pgpgout, PAGEROW + 3,
433 		PAGECOL + 10, 5);
434 	putrate(rate.v_pswpin, oldrate.v_pswpin, PAGEROW + 3,
435 		PAGECOL + 15, 5);
436 	putrate(rate.v_pswpout, oldrate.v_pswpout, PAGEROW + 3,
437 		PAGECOL + 20, 5);
438 	putrate(rate.v_pgrec, oldrate.v_pgrec, PAGEROW + 6, PAGECOL, 3);
439 	putrate(rate.v_intrans, oldrate.v_intrans, PAGEROW + 6,
440 		PAGECOL + 4, 2);
441 	putrate(rate.v_xsfrec, oldrate.v_xsfrec, PAGEROW + 6,
442 		PAGECOL + 7, 3);
443 	putrate(rate.v_xifrec, oldrate.v_xifrec, PAGEROW + 6,
444 		PAGECOL + 11, 3);
445 	putrate(rate.v_pgfrec, oldrate.v_pgfrec, PAGEROW + 6,
446 		PAGECOL + 15, 3);
447 	putrate(rate.v_dfree, oldrate.v_dfree, PAGEROW + 6,
448 		PAGECOL + 19, 3);
449 	putrate(rate.v_seqfree, oldrate.v_seqfree, PAGEROW + 6,
450 		PAGECOL + 23, 3);
451 	putrate(rate.v_zfod, oldrate.v_zfod, PAGEROW + 8, PAGECOL, 8);
452 	putrate(rate.v_nzfod, oldrate.v_nzfod, PAGEROW + 9, PAGECOL, 8);
453 	putrate(rate.v_exfod, oldrate.v_exfod, PAGEROW + 8,
454 		PAGECOL + 14, 8);
455 	putrate(rate.v_nexfod, oldrate.v_nexfod, PAGEROW + 9,
456 		PAGECOL + 14, 8);
457 	putfloat (
458 		rate.v_nzfod == 0 ?
459 			0.0
460 		: state != RUN ?
461 			( 100.0 * rate.v_zfod / rate.v_nzfod )
462 		: rate.v_nzfod == oldrate.v_nzfod ?
463 			0.0
464 		:
465 			( 100.0 * (rate.v_zfod-oldrate.v_zfod)
466 			/ (rate.v_nzfod-oldrate.v_nzfod) )
467 		, PAGEROW + 10
468 		, PAGECOL
469 		, 8
470 		, 2
471 		, 1
472 	);
473 	putfloat (
474 		rate.v_nexfod == 0 ?
475 			0.0
476 		: state != RUN ?
477 			( 100.0 * rate.v_exfod / rate.v_nexfod )
478 		: rate.v_nexfod == oldrate.v_nexfod ?
479 			0.0
480 		:
481 			( 100.0 * (rate.v_exfod-oldrate.v_exfod)
482 			/ (rate.v_nexfod-oldrate.v_nexfod) )
483 		, PAGEROW + 10
484 		, PAGECOL + 14
485 		, 8
486 		, 2
487 		, 1
488 	);
489 	mvprintw(DISKROW,DISKCOL+5,"                              ");
490 	for (i = 0, c = 0; i < dk_ndrive && c < MAXDRIVES; i++)
491 		if (dk_select[i]) {
492 			mvprintw(DISKROW, DISKCOL + 5 + 5 * c,
493 				"  %3.3s", dr_name[i]);
494 			dinfo(i, ++c);
495 		}
496 	putint(s.nchcount, NAMEIROW + 2, NAMEICOL, 9);
497 	putint(nchtotal.ncs_goodhits, NAMEIROW + 2, NAMEICOL + 9, 9);
498 #define nz(x)	((x) ? (x) : 1)
499 	putfloat(nchtotal.ncs_goodhits * 100.0 / nz(s.nchcount),
500 	   NAMEIROW + 2, NAMEICOL + 19, 4, 0, 1);
501 	putint(nchtotal.ncs_pass2, NAMEIROW + 2, NAMEICOL + 23, 9);
502 	putfloat(nchtotal.ncs_pass2 * 100.0 / nz(s.nchcount),
503 	   NAMEIROW + 2, NAMEICOL + 34, 4, 0, 1);
504 #undef nz
505 }
506 
507 cmdkre(cmd, args)
508 	char *cmd, *args;
509 {
510 
511 	if (prefix(cmd, "run")) {
512 		copyinfo(&s2, &s1);
513 		state = RUN;
514 		return (1);
515 	}
516 	if (prefix(cmd, "boot")) {
517 		state = BOOT;
518 		copyinfo(&z, &s1);
519 		return (1);
520 	}
521 	if (prefix(cmd, "time")) {
522 		state = TIME;
523 		return (1);
524 	}
525 	if (prefix(cmd, "zero")) {
526 		if (state == RUN)
527 			getinfo(&s1, RUN);
528 		return (1);
529 	}
530 	return (dkcmd(cmd, args));
531 }
532 
533 /* calculate number of users on the system */
534 static
535 ucount()
536 {
537 	register int nusers = 0;
538 
539 	if (ut < 0)
540 		return (0);
541 	while (read(ut, &utmp, sizeof(utmp)))
542 		if (utmp.ut_name[0] != '\0')
543 			nusers++;
544 
545 	lseek(ut, 0L, L_SET);
546 	return (nusers);
547 }
548 
549 static float
550 cputime(indx)
551 	int indx;
552 {
553 	double t;
554 	register i;
555 
556 	t = 0;
557 	for (i = 0; i < CPUSTATES; i++)
558 		t += s.time[i];
559 	if (t == 0.0)
560 		t = 1.0;
561 	return (s.time[indx] * 100.0 / t);
562 }
563 
564 static
565 putrate(r, or, l, c, w)
566 {
567 
568 	if (state != TIME) {
569 		if (state == RUN)
570 			r -= or;
571 		putint((int)((float)r/etime + 0.5), l, c, w);
572 	} else
573 		putint(r, l, c, w);
574 }
575 
576 static
577 putint(n, l, c, w)
578 {
579 	char b[128];
580 
581 	move(l, c);
582 	if (n == 0) {
583 		while (w-- > 0)
584 			addch(' ');
585 		return;
586 	}
587 	sprintf(b, "%*d", w, n);
588 	if (strlen(b) > w) {
589 		while (w-- > 0)
590 			addch('*');
591 		return;
592 	}
593 	addstr(b);
594 }
595 
596 static
597 putfloat(f, l, c, w, d, nz)
598 	float f;
599 {
600 	char b[128];
601 
602 	move(l, c);
603 	if (nz && f == 0.0) {
604 		while (w-- > 0)
605 			addch(' ');
606 		return;
607 	}
608 	sprintf(b, "%*.*f", w, d, f);
609 	if (strlen(b) > w) {
610 		while (w-- > 0)
611 			addch('*');
612 		return;
613 	}
614 	addstr(b);
615 }
616 
617 static
618 getinfo(s, st)
619 	struct Info *s;
620 	enum state st;
621 {
622 
623 	lseek(kmem, (long)name[X_CPTIME].n_value,L_SET);
624 	read(kmem, s->time, sizeof s->time);
625 	if (st != TIME) {
626 		lseek(kmem, (long)name[X_SUM].n_value, L_SET);
627 		read(kmem, &s->Rate, sizeof s->Rate);
628 	} else {
629 		lseek(kmem, (long)name[X_RATE].n_value,L_SET);
630 		read(kmem, &s->Rate, sizeof s->Rate);
631 	}
632 	lseek(kmem, (long)name[X_TOTAL].n_value, L_SET);
633 	read(kmem, &s->Total, sizeof s->Total);
634 	s->dk_busy = getw(name[X_DK_BUSY].n_value);
635  	lseek(kmem, (long)name[X_DK_TIME].n_value,  L_SET);
636  	read(kmem, s->dk_time, dk_ndrive * sizeof (long));
637  	lseek(kmem, (long)name[X_DK_XFER].n_value,  L_SET);
638  	read(kmem, s->dk_xfer, dk_ndrive * sizeof (long));
639  	lseek(kmem, (long)name[X_DK_WDS].n_value,  L_SET);
640  	read(kmem, s->dk_wds, dk_ndrive * sizeof (long));
641 	lseek(kmem, (long)name[X_DK_SEEK].n_value,  L_SET);
642 	read(kmem, s->dk_seek, dk_ndrive * sizeof (long));
643 	s->tk_nin = getw(name[X_TK_NIN].n_value);
644 	s->tk_nout = getw(name[X_TK_NOUT].n_value);
645 	lseek(kmem, (long)name[X_NCHSTATS].n_value,  L_SET);
646 	read(kmem, &s->nchstats, sizeof s->nchstats);
647 	lseek(kmem, (long)name[X_INTRCNT].n_value,  L_SET);
648 	read(kmem, s->intrcnt, nintr * sizeof (long));
649 }
650 
651 static
652 allocinfo(s)
653 	struct Info *s;
654 {
655 
656 	s->intrcnt = (long *) malloc(nintr * sizeof(long));
657 	if (s->intrcnt == NULL) {
658 		fprintf(stderr, "systat: out of memory\n");
659 		exit(2);
660 	}
661 }
662 
663 static
664 copyinfo(from, to)
665 	register struct Info *from, *to;
666 {
667 	long *time, *wds, *seek, *xfer;
668 	long *intrcnt;
669 
670 	time = to->dk_time; wds = to->dk_wds; seek = to->dk_seek;
671 	xfer = to->dk_xfer; intrcnt = to->intrcnt;
672 	*to = *from;
673 	bcopy(from->dk_time, to->dk_time = time, dk_ndrive * sizeof (long));
674 	bcopy(from->dk_wds, to->dk_wds = wds, dk_ndrive * sizeof (long));
675 	bcopy(from->dk_seek, to->dk_seek = seek, dk_ndrive * sizeof (long));
676 	bcopy(from->dk_xfer, to->dk_xfer = xfer, dk_ndrive * sizeof (long));
677 	bcopy(from->intrcnt, to->intrcnt = intrcnt, nintr * sizeof (int));
678 }
679 
680 static
681 dinfo(dn, c)
682 {
683 	double words, atime, itime, xtime;
684 
685 	c = DISKCOL + c * 5;
686 	atime = s.dk_time[dn];
687 	atime /= hertz;
688 	words = s.dk_wds[dn]*32.0;	/* number of words transferred */
689 	xtime = dk_mspw[dn]*words;	/* transfer time */
690 	itime = atime - xtime;		/* time not transferring */
691 	if (xtime < 0)
692 		itime += xtime, xtime = 0;
693 	if (itime < 0)
694 		xtime += itime, itime = 0;
695 	putint((int)((float)s.dk_seek[dn]/etime+0.5), DISKROW + 1, c, 5);
696 	putint((int)((float)s.dk_xfer[dn]/etime+0.5), DISKROW + 2, c, 5);
697 	putint((int)(words/etime/512.0 + 0.5), DISKROW + 3, c, 5);
698 	if (s.dk_seek[dn])
699 		putfloat(itime*1000.0/s.dk_seek[dn], DISKROW + 4, c, 5, 1, 1);
700 	else
701 		putint(0, DISKROW + 4, c, 5);
702 }
703