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