manual page distributed with 4.1BSD
[unix-history] / usr / src / usr.bin / vmstat / vmstat.c
CommitLineData
338c4a5d 1#ifndef lint
196ccf10 2static char *sccsid = "@(#)vmstat.c 4.18 (Berkeley) %G%";
338c4a5d
SL
3#endif
4
7f02df2f 5#include <stdio.h>
a448353a
SL
6#include <ctype.h>
7#include <nlist.h>
8
7f02df2f 9#include <sys/param.h>
a448353a 10#include <sys/file.h>
7f02df2f
BJ
11#include <sys/vm.h>
12#include <sys/dk.h>
61d7d2b3 13#include <sys/buf.h>
dfdfb4c8 14#include <sys/dir.h>
a448353a 15#include <sys/inode.h>
4b894a2c 16#include <sys/namei.h>
7f02df2f
BJ
17
18struct nlist nl[] = {
682f1dcb
BJ
19#define X_CPTIME 0
20 { "_cp_time" },
21#define X_RATE 1
7f02df2f 22 { "_rate" },
682f1dcb 23#define X_TOTAL 2
7f02df2f 24 { "_total" },
682f1dcb 25#define X_DEFICIT 3
7f02df2f 26 { "_deficit" },
682f1dcb 27#define X_FORKSTAT 4
7f02df2f 28 { "_forkstat" },
682f1dcb 29#define X_SUM 5
7f02df2f 30 { "_sum" },
682f1dcb 31#define X_FIRSTFREE 6
7f02df2f 32 { "_firstfree" },
682f1dcb 33#define X_MAXFREE 7
7f02df2f 34 { "_maxfree" },
a43be079
SL
35#define X_BOOTTIME 8
36 { "_boottime" },
682f1dcb
BJ
37#define X_DKXFER 9
38 { "_dk_xfer" },
338c4a5d 39#define X_REC 10
7f02df2f 40 { "_rectime" },
338c4a5d 41#define X_PGIN 11
7f02df2f 42 { "_pgintime" },
338c4a5d 43#define X_HZ 12
61d7d2b3 44 { "_hz" },
a448353a 45#define X_PHZ 13
b3a37270 46 { "_phz" },
dfdfb4c8
KM
47#define X_NCHSTATS 14
48 { "_nchstats" },
4b894a2c
KM
49#define X_INTRNAMES 15
50 { "_intrnames" },
51#define X_EINTRNAMES 16
52 { "_eintrnames" },
53#define X_INTRCNT 17
54 { "_intrcnt" },
55#define X_EINTRCNT 18
56 { "_eintrcnt" },
a448353a
SL
57#define X_DK_NDRIVE 19
58 { "_dk_ndrive" },
338c4a5d 59#ifdef vax
a448353a 60#define X_MBDINIT 20
338c4a5d 61 { "_mbdinit" },
a448353a 62#define X_UBDINIT 21
338c4a5d 63 { "_ubdinit" },
338c4a5d
SL
64#endif
65 { "" },
7f02df2f
BJ
66};
67
a448353a
SL
68char **dr_name;
69int *dr_select;
70int dk_ndrive;
71int ndrives = 0;
72#ifdef vax
73char *defdrives[] = { "hp0", "hp1", "hp2", 0 };
74#else
75char *defdrives[] = { 0 };
76#endif
7f02df2f
BJ
77double stat1();
78int firstfree, maxfree;
61d7d2b3 79int hz;
b3a37270
SL
80int phz;
81int HZ;
a448353a 82
b3a37270
SL
83#ifdef vax
84#define INTS(x) ((x) - (hz + phz))
85#endif
86
a448353a 87struct {
7f02df2f 88 int busy;
682f1dcb 89 long time[CPUSTATES];
a448353a 90 long *xfer;
7f02df2f
BJ
91 struct vmmeter Rate;
92 struct vmtotal Total;
93 struct vmmeter Sum;
94 struct forkstat Forkstat;
7f02df2f
BJ
95 unsigned rectime;
96 unsigned pgintime;
7f02df2f
BJ
97} s, s1, z;
98#define rate s.Rate
99#define total s.Total
100#define sum s.Sum
101#define forkstat s.Forkstat
102
338c4a5d 103struct vmmeter osum;
7f02df2f
BJ
104int zero;
105int deficit;
106double etime;
107int mf;
4b894a2c
KM
108time_t now, boottime;
109int printhdr();
196ccf10 110int lines = 1;
7f02df2f
BJ
111
112main(argc, argv)
338c4a5d
SL
113 int argc;
114 char **argv;
7f02df2f 115{
7f02df2f
BJ
116 extern char *ctime();
117 register i,j;
4b894a2c 118 int iter, nintv, iflag = 0;
7f02df2f
BJ
119 double f1, f2;
120 long t;
a448353a 121 char *arg, **cp, name[6], buf[BUFSIZ];
7f02df2f 122
7f02df2f
BJ
123 nlist("/vmunix", nl);
124 if(nl[0].n_type == 0) {
125 printf("no /vmunix namelist\n");
126 exit(1);
127 }
128 mf = open("/dev/kmem", 0);
129 if(mf < 0) {
130 printf("cannot open /dev/kmem\n");
131 exit(1);
132 }
133 iter = 0;
134 argc--, argv++;
135 while (argc>0 && argv[0][0]=='-') {
136 char *cp = *argv++;
137 argc--;
138 while (*++cp) switch (*cp) {
139
7f02df2f
BJ
140 case 't':
141 dotimes();
142 exit(0);
338c4a5d 143
7f02df2f
BJ
144 case 'z':
145 close(mf);
146 mf = open("/dev/kmem", 2);
a448353a 147 lseek(mf, (long)nl[X_SUM].n_value, L_SET);
7f02df2f
BJ
148 write(mf, &z.Sum, sizeof z.Sum);
149 exit(0);
150
151 case 'f':
152 doforkst();
153 exit(0);
154
155 case 's':
156 dosum();
157 exit(0);
158
4b894a2c
KM
159 case 'i':
160 iflag++;
161 break;
162
7f02df2f 163 default:
a448353a
SL
164 fprintf(stderr,
165 "usage: vmstat [ -fsi ] [ interval ] [ count]\n");
7f02df2f
BJ
166 exit(1);
167 }
168 }
a448353a 169 lseek(mf, (long)nl[X_FIRSTFREE].n_value, L_SET);
7f02df2f 170 read(mf, &firstfree, sizeof firstfree);
a448353a 171 lseek(mf, (long)nl[X_MAXFREE].n_value, L_SET);
7f02df2f 172 read(mf, &maxfree, sizeof maxfree);
a448353a 173 lseek(mf, (long)nl[X_BOOTTIME].n_value, L_SET);
a43be079 174 read(mf, &boottime, sizeof boottime);
a448353a 175 lseek(mf, (long)nl[X_HZ].n_value, L_SET);
61d7d2b3 176 read(mf, &hz, sizeof hz);
a448353a
SL
177 if (nl[X_PHZ].n_value != 0) {
178 lseek(mf, (long)nl[X_PHZ].n_value, L_SET);
179 read(mf, &phz, sizeof phz);
180 }
b3a37270 181 HZ = phz ? phz : hz;
a448353a
SL
182 if (nl[DK_NDRIVE].n_value == 0) {
183 printf("dk_ndrive undefined in system\n");
184 exit(1);
185 }
186 lseek(mf, nl[X_DK_NDRIVE].n_value, L_SET);
187 read(mf, &dk_ndrive, sizeof (dk_ndrive));
188 if (dk_ndrive <= 0) {
189 printf("dk_ndrive %d\n", dk_ndrive);
190 exit(1);
191 }
192 dr_select = (int *)calloc(dk_ndrive, sizeof (int));
193 dr_name = (char **)calloc(dk_ndrive, sizeof (char *));
194#define allocate(e, t) \
195 s./**/e = (t *)calloc(dk_ndrive, sizeof (t)); \
196 s1./**/e = (t *)calloc(dk_ndrive, sizeof (t));
197 allocate(xfer, long);
198 for (arg = buf, i = 0; i < dk_ndrive; i++) {
199 dr_name[i] = arg;
200 sprintf(dr_name[i], "dk%d", i);
201 arg += strlen(dr_name[i]) + 1;
61d7d2b3
MT
202 }
203 read_names();
7f02df2f 204 time(&now);
a43be079 205 nintv = now - boottime;
7f02df2f
BJ
206 if (nintv <= 0 || nintv > 60*60*24*365*10) {
207 printf("Time makes no sense... namelist must be wrong.\n");
208 exit(1);
209 }
4b894a2c
KM
210 if (iflag) {
211 dointr(nintv);
212 exit(0);
213 }
a448353a
SL
214 /*
215 * Choose drives to be displayed. Priority
216 * goes to (in order) drives supplied as arguments,
217 * default drives. If everything isn't filled
218 * in and there are drives not taken care of,
219 * display the first few that fit.
220 */
221 ndrives = 0;
222 while (argc > 0 && !isdigit(argv[0][0])) {
223 for (i = 0; i < dk_ndrive; i++) {
224 if (strcmp(dr_name[i], argv[0]))
225 continue;
226 dr_select[i] = 1;
227 ndrives++;
228 }
229 argc--, argv++;
230 }
231 for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
232 if (dr_select[i])
233 continue;
234 for (cp = defdrives; *cp; cp++)
235 if (strcmp(dr_name[i], *cp) == 0) {
236 dr_select[i] = 1;
237 ndrives++;
238 break;
239 }
240 }
241 for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
242 if (dr_select[i])
243 continue;
244 dr_select[i] = 1;
245 ndrives++;
246 }
247 if (argc > 1)
248 iter = atoi(argv[1]);
4b894a2c 249 signal(SIGCONT, printhdr);
7f02df2f 250loop:
196ccf10
SL
251 if (--lines == 0)
252 printhdr();
a448353a 253 lseek(mf, (long)nl[X_CPTIME].n_value, L_SET);
682f1dcb 254 read(mf, s.time, sizeof s.time);
a448353a
SL
255 lseek(mf, (long)nl[X_DKXFER].n_value, L_SET);
256 read(mf, s.xfer, dk_ndrive * sizeof (long));
257 if (nintv != 1)
258 lseek(mf, (long)nl[X_SUM].n_value, L_SET);
259 else
260 lseek(mf, (long)nl[X_RATE].n_value, L_SET);
261 read(mf, &rate, sizeof rate);
262 lseek(mf, (long)nl[X_TOTAL].n_value, L_SET);
7f02df2f 263 read(mf, &total, sizeof total);
338c4a5d 264 osum = sum;
a448353a 265 lseek(mf, (long)nl[X_SUM].n_value, L_SET);
338c4a5d 266 read(mf, &sum, sizeof sum);
a448353a 267 lseek(mf, (long)nl[X_DEFICIT].n_value, L_SET);
7f02df2f 268 read(mf, &deficit, sizeof deficit);
682f1dcb 269 etime = 0;
a448353a 270 for (i=0; i < dk_ndrive; i++) {
682f1dcb
BJ
271 t = s.xfer[i];
272 s.xfer[i] -= s1.xfer[i];
273 s1.xfer[i] = t;
7f02df2f
BJ
274 }
275 for (i=0; i < CPUSTATES; i++) {
682f1dcb
BJ
276 t = s.time[i];
277 s.time[i] -= s1.time[i];
278 s1.time[i] = t;
279 etime += s.time[i];
7f02df2f 280 }
7f02df2f
BJ
281 if(etime == 0.)
282 etime = 1.;
61d7d2b3 283 printf("%2d%2d%2d", total.t_rq, total.t_dw+total.t_pw, total.t_sw);
338c4a5d
SL
284#define pgtok(a) ((a)*NBPG/1024)
285 printf("%6d%5d", pgtok(total.t_avm), pgtok(total.t_free));
b3a37270
SL
286 printf("%4d%3d", (rate.v_pgrec - (rate.v_xsfrec+rate.v_xifrec))/nintv,
287 (rate.v_xsfrec+rate.v_xifrec)/nintv);
338c4a5d
SL
288 printf("%4d", pgtok(rate.v_pgpgin)/nintv);
289 printf("%4d%4d%4d%4d", pgtok(rate.v_pgpgout)/nintv,
290 pgtok(rate.v_dfree)/nintv, pgtok(deficit), rate.v_scan/nintv);
a448353a
SL
291 etime /= (float)HZ;
292 for (i = 0; i < dk_ndrive; i++)
293 if (dr_select[i])
294 stats(i);
b3a37270
SL
295 printf("%4d%4d%4d", INTS(rate.v_intr/nintv), rate.v_syscall/nintv,
296 rate.v_swtch/nintv);
7f02df2f
BJ
297 for(i=0; i<CPUSTATES; i++) {
298 float f = stat1(i);
299 if (i == 0) { /* US+NI */
300 i++;
301 f += stat1(i);
302 }
303 printf("%3.0f", f);
304 }
305 printf("\n");
306 fflush(stdout);
307contin:
308 nintv = 1;
196ccf10 309 if (--iter &&argc > 0) {
7f02df2f 310 sleep(atoi(argv[0]));
7f02df2f
BJ
311 goto loop;
312 }
313}
314
4b894a2c
KM
315printhdr()
316{
a448353a
SL
317 register int i, j;
318
319 printf(" procs memory page ");
320 i = (ndrives * 3 - 6) / 2;
321 if (i < 0)
322 i = 0;
323 for (j = 0; j < i; j++)
324 putchar(' ');
325 printf("faults");
326 i = ndrives * 3 - 6 - i;
327 for (j = 0; j < i; j++)
328 putchar(' ');
329 printf(" cpu\n");
330 printf(" r b w avm fre re at pi po fr de sr ");
331 for (i = 0; i < dk_ndrive; i++)
332 if (dr_select[i])
333 printf("%c%c ", dr_name[i][0], dr_name[i][2]);
334 printf(" in sy cs us sy id\n");
196ccf10 335 lines = 19;
4b894a2c
KM
336}
337
7f02df2f
BJ
338dotimes()
339{
340
a448353a 341 lseek(mf, (long)nl[X_REC].n_value, L_SET);
7f02df2f 342 read(mf, &s.rectime, sizeof s.rectime);
a448353a 343 lseek(mf, (long)nl[X_PGIN].n_value, L_SET);
7f02df2f 344 read(mf, &s.pgintime, sizeof s.pgintime);
a448353a 345 lseek(mf, (long)nl[X_SUM].n_value, L_SET);
7f02df2f
BJ
346 read(mf, &sum, sizeof sum);
347 printf("%d reclaims, %d total time (usec)\n", sum.v_pgrec, s.rectime);
348 printf("average: %d usec / reclaim\n", s.rectime/sum.v_pgrec);
349 printf("\n");
350 printf("%d page ins, %d total time (msec)\n",sum.v_pgin, s.pgintime/10);
351 printf("average: %8.1f msec / page in\n", s.pgintime/(sum.v_pgin*10.0));
352}
7f02df2f
BJ
353
354dosum()
355{
a448353a 356 struct nchstats nchstats;
dfdfb4c8 357 long nchtotal;
7f02df2f 358
a448353a 359 lseek(mf, (long)nl[X_SUM].n_value, L_SET);
7f02df2f
BJ
360 read(mf, &sum, sizeof sum);
361 printf("%9d swap ins\n", sum.v_swpin);
362 printf("%9d swap outs\n", sum.v_swpout);
363 printf("%9d pages swapped in\n", sum.v_pswpin / CLSIZE);
364 printf("%9d pages swapped out\n", sum.v_pswpout / CLSIZE);
365 printf("%9d total address trans. faults taken\n", sum.v_faults);
366 printf("%9d page ins\n", sum.v_pgin);
367 printf("%9d page outs\n", sum.v_pgout);
513dfff1
BJ
368 printf("%9d pages paged in\n", sum.v_pgpgin);
369 printf("%9d pages paged out\n", sum.v_pgpgout);
370 printf("%9d sequential process pages freed\n", sum.v_seqfree);
e23f616a
SL
371 printf("%9d total reclaims (%d%% fast)\n", sum.v_pgrec,
372 (sum.v_fastpgrec * 100) / (sum.v_pgrec == 0 ? 1 : sum.v_pgrec));
7f02df2f
BJ
373 printf("%9d reclaims from free list\n", sum.v_pgfrec);
374 printf("%9d intransit blocking page faults\n", sum.v_intrans);
375 printf("%9d zero fill pages created\n", sum.v_nzfod / CLSIZE);
376 printf("%9d zero fill page faults\n", sum.v_zfod / CLSIZE);
377 printf("%9d executable fill pages created\n", sum.v_nexfod / CLSIZE);
378 printf("%9d executable fill page faults\n", sum.v_exfod / CLSIZE);
379 printf("%9d swap text pages found in free list\n", sum.v_xsfrec);
380 printf("%9d inode text pages found in free list\n", sum.v_xifrec);
381 printf("%9d file fill pages created\n", sum.v_nvrfod / CLSIZE);
382 printf("%9d file fill page faults\n", sum.v_vrfod / CLSIZE);
383 printf("%9d pages examined by the clock daemon\n", sum.v_scan);
384 printf("%9d revolutions of the clock hand\n", sum.v_rev);
385 printf("%9d pages freed by the clock daemon\n", sum.v_dfree / CLSIZE);
386 printf("%9d cpu context switches\n", sum.v_swtch);
387 printf("%9d device interrupts\n", sum.v_intr);
4b894a2c 388 printf("%9d software interrupts\n", sum.v_soft);
a448353a 389#ifdef vax
7f02df2f 390 printf("%9d pseduo-dma dz interrupts\n", sum.v_pdma);
a448353a 391#endif
7f02df2f
BJ
392 printf("%9d traps\n", sum.v_trap);
393 printf("%9d system calls\n", sum.v_syscall);
dfdfb4c8 394 lseek(mf, (long)nl[X_NCHSTATS].n_value, 0);
a448353a
SL
395 read(mf, &nchstats, sizeof nchstats);
396 nchtotal = nchstats.ncs_goodhits + nchstats.ncs_badhits +
397 nchstats.ncs_falsehits + nchstats.ncs_miss + nchstats.ncs_long;
dfdfb4c8 398 printf("%9d total name lookups", nchtotal);
c8520a5c 399#define nz(x) ((x) ? (x) : 1)
dfdfb4c8 400 printf(" (cache hits %d%% system %d%% per-process)\n",
a448353a
SL
401 nchstats.ncs_goodhits * 100 / nz(nchtotal),
402 nchstats.ncs_pass2 * 100 / nz(nchtotal));
c8520a5c 403 printf("%9s badhits %d, falsehits %d, toolong %d\n", "",
a448353a 404 nchstats.ncs_badhits, nchstats.ncs_falsehits, nchstats.ncs_long);
7f02df2f
BJ
405}
406
7f02df2f
BJ
407doforkst()
408{
409
a448353a 410 lseek(mf, (long)nl[X_FORKSTAT].n_value, L_SET);
7f02df2f
BJ
411 read(mf, &forkstat, sizeof forkstat);
412 printf("%d forks, %d pages, average=%.2f\n",
413 forkstat.cntfork, forkstat.sizfork,
414 (float) forkstat.sizfork / forkstat.cntfork);
415 printf("%d vforks, %d pages, average=%.2f\n",
416 forkstat.cntvfork, forkstat.sizvfork,
417 (float)forkstat.sizvfork / forkstat.cntvfork);
418}
419
420stats(dn)
421{
422
a448353a 423 if (dn >= dk_ndrive) {
7f02df2f
BJ
424 printf(" 0");
425 return;
426 }
682f1dcb 427 printf("%3.0f", s.xfer[dn]/etime);
7f02df2f
BJ
428}
429
430double
431stat1(row)
432{
682f1dcb
BJ
433 double t;
434 register i;
7f02df2f
BJ
435
436 t = 0;
437 for(i=0; i<CPUSTATES; i++)
682f1dcb
BJ
438 t += s.time[i];
439 if(t == 0.)
440 t = 1.;
441 return(s.time[row]*100./t);
7f02df2f
BJ
442}
443
444pct(top, bot)
445{
446
447 if (bot == 0)
448 return (0);
449 return ((top * 100) / bot);
450}
61d7d2b3 451
4b894a2c
KM
452dointr(nintv)
453{
454 int nintr, inttotal;
455 long *intrcnt;
456 char *intrname, *malloc();
457
458 nintr = (nl[X_EINTRCNT].n_value - nl[X_INTRCNT].n_value) / sizeof(long);
459 intrcnt = (long *) malloc(nl[X_EINTRCNT].n_value -
460 nl[X_INTRCNT].n_value);
461 intrname = malloc(nl[X_EINTRNAMES].n_value - nl[X_INTRNAMES].n_value);
462 if (intrcnt == NULL || intrname == NULL) {
463 fprintf(stderr, "vmstat: out of memory\n");
464 exit(9);
465 }
a448353a 466 lseek(mf, (long)nl[X_INTRCNT].n_value, L_SET);
4b894a2c 467 read(mf, intrcnt, nintr * sizeof (long));
a448353a 468 lseek(mf, (long)nl[X_INTRNAMES].n_value, L_SET);
4b894a2c
KM
469 read(mf, intrname, nl[X_EINTRNAMES].n_value - nl[X_INTRNAMES].n_value);
470 printf("interrupt total rate\n");
471 inttotal = 0;
472 while (nintr--) {
473 if (*intrcnt)
474 printf("%-12s %8ld %8ld\n", intrname,
475 *intrcnt, *intrcnt / nintv);
476 intrname += strlen(intrname) + 1;
477 inttotal += *intrcnt++;
478 }
479 printf("Total %8ld %8ld\n", inttotal, inttotal / nintv);
480}
481
a448353a
SL
482#define steal(where, var) \
483 lseek(mf, where, L_SET); read(mf, &var, sizeof var);
61d7d2b3
MT
484/*
485 * Read the drive names out of kmem.
61d7d2b3 486 */
338c4a5d 487#ifdef vax
a448353a
SL
488#include <vaxuba/ubavar.h>
489#include <vaxmba/mbavar.h>
490
61d7d2b3
MT
491read_names()
492{
493 struct mba_device mdev;
494 register struct mba_device *mp;
495 struct mba_driver mdrv;
496 short two_char;
497 char *cp = (char *) &two_char;
498 struct uba_device udev, *up;
499 struct uba_driver udrv;
500
501 mp = (struct mba_device *) nl[X_MBDINIT].n_value;
502 up = (struct uba_device *) nl[X_UBDINIT].n_value;
93ca0bfe 503 if (up == 0) {
338c4a5d 504 fprintf(stderr, "vmstat: Disk init info not in namelist\n");
61d7d2b3
MT
505 exit(1);
506 }
93ca0bfe 507 if (mp) for (;;) {
61d7d2b3
MT
508 steal(mp++, mdev);
509 if (mdev.mi_driver == 0)
510 break;
511 if (mdev.mi_dk < 0 || mdev.mi_alive == 0)
512 continue;
513 steal(mdev.mi_driver, mdrv);
514 steal(mdrv.md_dname, two_char);
a448353a
SL
515 sprintf(dr_name[mdev.mi_dk], "%c%c%d",
516 cp[0], cp[1], mdev.mi_unit);
61d7d2b3 517 }
93ca0bfe 518 for (;;) {
61d7d2b3
MT
519 steal(up++, udev);
520 if (udev.ui_driver == 0)
521 break;
522 if (udev.ui_dk < 0 || udev.ui_alive == 0)
523 continue;
524 steal(udev.ui_driver, udrv);
525 steal(udrv.ud_dname, two_char);
a448353a
SL
526 sprintf(dr_name[udev.ui_dk], "%c%c%d",
527 cp[0], cp[1], udev.ui_unit);
61d7d2b3
MT
528 }
529}
338c4a5d 530#endif