1 /* 2 * Copyright (c) 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)vmstat.c 8.1 (Berkeley) 06/06/93"; 10 #endif /* not lint */ 11 12 #include <sys/param.h> 13 #include <sys/device.h> 14 #include <sys/disklabel.h> 15 #include <sys/disk.h> 16 #include <sys/time.h> 17 #include <sys/dkstat.h> 18 #include <sys/ioctl.h> 19 #include <sys/sysctl.h> 20 #include <vm/vm.h> 21 22 #include <errno.h> 23 #include <kvm.h> 24 #include <limits.h> 25 #include <nlist.h> 26 #include <signal.h> 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <string.h> 30 #include <time.h> 31 #include <unistd.h> 32 33 #include "extern.h" 34 35 int hz, hdrcnt, winlines; 36 37 struct { 38 long old[CPUSTATES]; /* previous cp_time from kernel */ 39 long delta[CPUSTATES]; /* delta between current & prev */ 40 long total; /* sum of deltas */ 41 } cputime; 42 43 void cpustats __P((void)); 44 void dkstats __P((void)); 45 void getcputime __P(()); 46 int getwinsize __P((void)); 47 void needhdr __P((int)); 48 void printhdr __P((void)); 49 50 static struct nlist nl[] = { 51 { "_cnt" }, 52 #define X_CNT 0 53 { "_cp_time" }, 54 #define X_CPTIME 1 55 0 56 }; 57 58 void 59 dovmstat(interval, reps) 60 u_int interval; 61 int reps; 62 { 63 int mib[2], size; 64 time_t uptime, halfuptime; 65 struct clockinfo ci; 66 struct vmtotal total; 67 struct vmmeter cnt, ocnt; 68 69 knlist(nl); 70 winlines = getwinsize(); 71 uptime = getuptime(); 72 halfuptime = uptime / 2; 73 (void)signal(SIGCONT, needhdr); 74 size = sizeof(ci); 75 mib[0] = CTL_KERN; 76 mib[1] = KERN_CLOCKRATE; 77 if (sysctl(mib, 2, &ci, &size, NULL, 0) < 0) 78 errexit("sysctl(KERN_CLOCKRATE): %s\n", strerror(errno)); 79 hz = ci.stathz ? ci.stathz : ci.hz; 80 for (hdrcnt = 1;;) { 81 if (--hdrcnt == 0) 82 printhdr(); 83 kread(nl[X_CNT].n_value, &cnt, sizeof cnt, "cnt"); 84 getcputime(); 85 size = sizeof(total); 86 mib[0] = CTL_VM; 87 mib[1] = VM_METER; 88 if (sysctl(mib, 2, &total, &size, NULL, 0) < 0) 89 errexit("sysctl(VM_METER): %s\n", strerror(errno)); 90 (void)printf("%2d%2d%2d", 91 total.t_rq, total.t_dw + total.t_pw, total.t_sw); 92 #define pgtok(a) ((a) * cnt.v_page_size >> 10) 93 #define rate(x) (((x) + halfuptime) / uptime) /* round */ 94 (void)printf("%6ld%6ld ", 95 pgtok(total.t_avm), pgtok(total.t_free)); 96 (void)printf("%4lu ", rate(cnt.v_faults - ocnt.v_faults)); 97 (void)printf("%3lu ", 98 rate(cnt.v_reactivated - ocnt.v_reactivated)); 99 (void)printf("%3lu ", rate(cnt.v_pageins - ocnt.v_pageins)); 100 (void)printf("%3lu %3lu ", 101 rate(cnt.v_pageouts - ocnt.v_pageouts), 0); 102 (void)printf("%3lu ", rate(cnt.v_scan - ocnt.v_scan)); 103 dkstats(); 104 (void)printf("%4lu %4lu %3lu ", 105 rate(cnt.v_intr - ocnt.v_intr), 106 rate(cnt.v_syscall - ocnt.v_syscall), 107 rate(cnt.v_swtch - ocnt.v_swtch)); 108 cpustats(); 109 (void)printf("\n"); 110 (void)fflush(stdout); 111 if (reps >= 0 && --reps <= 0) 112 break; 113 ocnt = cnt; 114 uptime = interval; 115 /* 116 * We round upward to avoid losing low-frequency events 117 * (i.e., >= 1 per interval but < 1 per second). 118 */ 119 halfuptime = (uptime + 1) / 2; 120 (void)sleep(interval); 121 } 122 } 123 124 int 125 getwinsize() 126 { 127 struct winsize winsize; 128 129 winsize.ws_row = 0; 130 (void) ioctl(STDOUT_FILENO, TIOCGWINSZ, (char *)&winsize); 131 return (winsize.ws_row > 0 ? winsize.ws_row : 20); 132 } 133 134 /* 135 * Get cpu times for dkstats and cpustats(). 136 */ 137 void 138 getcputime() 139 { 140 register int state; 141 long t, sum, cp_time[CPUSTATES]; 142 143 kread(nl[X_CPTIME].n_value, cp_time, sizeof cp_time, "cp_time"); 144 for (sum = 0, state = 0; state < CPUSTATES; ++state) { 145 t = cp_time[state] - cputime.old[state]; 146 cputime.old[state] = cp_time[state]; 147 cputime.delta[state] = t; 148 sum += t; 149 } 150 cputime.total = sum; 151 } 152 153 /* 154 * Print disk statistics for dovmstat(). 155 */ 156 void 157 dkstats() 158 { 159 register struct dkinfo *dk; 160 double etime; 161 #ifdef notyet 162 long xfer; 163 164 for (dk = dkinfo; dk != NULL; dk = dk->dk_next) { 165 kread(addr + offsetof(struct dkdevice, dk_xfer), 166 &xfer, sizeof xfer, dk->dk_name); 167 dk->dk_dxfer = xfer - dk->dk_oxfer; 168 dk->dk_oxfer = xfer; 169 } 170 #endif 171 etime = (cputime.total ? (double)cputime.total : 1.0) / hz; 172 for (dk = dkinfo; dk != NULL; dk = dk->dk_next) 173 if (dk->dk_sel) 174 (void)printf("%2.0f ", dk->dk_dxfer / etime); 175 } 176 177 /* 178 * Print cpu statistics for dovmstat(). 179 */ 180 void 181 cpustats() 182 { 183 double pct; 184 185 if (cputime.total) 186 pct = 100.0 / cputime.total; 187 else 188 pct = 0.0; 189 (void)printf("%2.0f %2.0f %2.0f", 190 (cputime.delta[CP_USER] + cputime.delta[CP_NICE]) * pct, 191 (cputime.delta[CP_SYS] + cputime.delta[CP_INTR]) * pct, 192 cputime.delta[CP_IDLE] * pct); 193 } 194 195 void 196 printhdr() 197 { 198 register struct dkinfo *dk; 199 200 (void)printf(" procs memory page%*s", 20, ""); 201 if (ndrives > 1) 202 (void)printf("disks %*s faults cpu\n", 203 ndrives * 3 - 6, ""); 204 else 205 (void)printf("%*s faults cpu\n", ndrives * 3, ""); 206 (void)printf(" r b w avm fre flt re pi po fr sr "); 207 for (dk = dkinfo; dk != NULL; dk = dk->dk_next) 208 if (dk->dk_sel) 209 (void)printf("%s ", dk->dk_2c); 210 (void)printf(" in sy cs us sy id\n"); 211 hdrcnt = winlines - 2; 212 } 213 214 /* 215 * Force a header to be prepended to the next output. 216 */ 217 void 218 needhdr(sig) 219 int sig; 220 { 221 222 hdrcnt = 1; 223 } 224