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