Commit | Line | Data |
---|---|---|
cf1d1622 | 1 | /*- |
d3f8ef0e | 2 | * Copyright (c) 1986, 1991 The Regents of the University of California. |
cf1d1622 KB |
3 | * All rights reserved. |
4 | * | |
9835199b | 5 | * %sccs.include.redist.c% |
cf1d1622 KB |
6 | */ |
7 | ||
94f8dc1b | 8 | #ifndef lint |
cf1d1622 | 9 | char copyright[] = |
d3f8ef0e | 10 | "@(#) Copyright (c) 1986, 1991 The Regents of the University of California.\n\ |
cf1d1622 KB |
11 | All rights reserved.\n"; |
12 | #endif /* not lint */ | |
13 | ||
14 | #ifndef lint | |
413f7539 | 15 | static char sccsid[] = "@(#)iostat.c 5.15 (Berkeley) %G%"; |
cf1d1622 | 16 | #endif /* not lint */ |
94f8dc1b | 17 | |
9835199b | 18 | #include <sys/param.h> |
700789be | 19 | #include <sys/buf.h> |
b0c469a3 | 20 | #include <sys/dkstat.h> |
d3f8ef0e KB |
21 | #include <signal.h> |
22 | #include <fcntl.h> | |
23 | #include <nlist.h> | |
24 | #include <unistd.h> | |
7abf8d65 KB |
25 | #include <stdio.h> |
26 | #include <ctype.h> | |
d3f8ef0e KB |
27 | #include <stdlib.h> |
28 | #include <string.h> | |
7abf8d65 | 29 | #include <paths.h> |
114fa233 | 30 | #include <kvm.h> |
100709ca | 31 | #include <limits.h> |
be974f30 BJ |
32 | |
33 | struct nlist nl[] = { | |
703187b4 | 34 | #define X_DK_TIME 0 |
114fa233 | 35 | { "_dk_time" }, |
703187b4 | 36 | #define X_DK_XFER 1 |
114fa233 | 37 | { "_dk_xfer" }, |
703187b4 | 38 | #define X_DK_WDS 2 |
114fa233 | 39 | { "_dk_wds" }, |
703187b4 | 40 | #define X_TK_NIN 3 |
114fa233 | 41 | { "_tk_nin" }, |
703187b4 | 42 | #define X_TK_NOUT 4 |
114fa233 | 43 | { "_tk_nout" }, |
703187b4 | 44 | #define X_DK_SEEK 5 |
114fa233 | 45 | { "_dk_seek" }, |
703187b4 | 46 | #define X_CP_TIME 6 |
114fa233 | 47 | { "_cp_time" }, |
703187b4 | 48 | #define X_DK_WPMS 7 |
114fa233 | 49 | { "_dk_wpms" }, |
703187b4 | 50 | #define X_HZ 8 |
114fa233 | 51 | { "_hz" }, |
100709ca SM |
52 | #define X_STATHZ 9 |
53 | { "_stathz" }, | |
703187b4 | 54 | #define X_DK_NDRIVE 10 |
114fa233 | 55 | { "_dk_ndrive" }, |
8dbdac03 | 56 | #define X_END 10 |
413f7539 | 57 | #if defined(hp300) || defined(luna68k) |
114fa233 KB |
58 | #define X_HPDINIT (X_END+1) |
59 | { "_hp_dinit" }, | |
b0c469a3 SL |
60 | #endif |
61 | #ifdef tahoe | |
114fa233 | 62 | #define X_VBDINIT (X_END+1) |
b0c469a3 | 63 | { "_vbdinit" }, |
41b4a915 | 64 | #endif |
94f8dc1b | 65 | #ifdef vax |
114fa233 KB |
66 | { "_mbdinit" }, |
67 | #define X_MBDINIT (X_END+1) | |
68 | { "_ubdinit" }, | |
69 | #define X_UBDINIT (X_END+2) | |
94f8dc1b | 70 | #endif |
703187b4 | 71 | { NULL }, |
114fa233 | 72 | }; |
700789be | 73 | |
114fa233 | 74 | struct _disk { |
be974f30 | 75 | long cp_time[CPUSTATES]; |
94f8dc1b SL |
76 | long *dk_time; |
77 | long *dk_wds; | |
78 | long *dk_seek; | |
79 | long *dk_xfer; | |
be974f30 BJ |
80 | long tk_nin; |
81 | long tk_nout; | |
114fa233 KB |
82 | } cur, last; |
83 | ||
84 | double etime; | |
85 | long *dk_wpms; | |
86 | int dk_ndrive, *dr_select, hz, kmemfd, ndrives; | |
87 | char **dr_name; | |
88 | ||
100709ca SM |
89 | kvm_t *kd; |
90 | ||
114fa233 | 91 | #define nlread(x, v) \ |
100709ca | 92 | kvm_read(kd, nl[x].n_value, &(v), sizeof(v)) |
be974f30 | 93 | |
703187b4 KB |
94 | #include "names.c" /* XXX */ |
95 | ||
8542228e KB |
96 | void cpustats __P((void)); |
97 | void dkstats __P((void)); | |
98 | void err __P((const char *, ...)); | |
99 | void phdr __P((int)); | |
100 | void usage __P((void)); | |
703187b4 | 101 | |
be974f30 | 102 | main(argc, argv) |
d3f8ef0e KB |
103 | int argc; |
104 | char **argv; | |
be974f30 | 105 | { |
d3f8ef0e | 106 | register int i; |
114fa233 | 107 | long tmp; |
100709ca | 108 | int ch, hdrcnt, reps, interval, stathz, ndrives; |
ad07e3a9 | 109 | char **cp, *memf, *nlistf, buf[30]; |
100709ca | 110 | char errbuf[_POSIX2_LINE_MAX]; |
d3f8ef0e KB |
111 | |
112 | interval = reps = 0; | |
ad07e3a9 | 113 | nlistf = memf = NULL; |
3cead284 | 114 | while ((ch = getopt(argc, argv, "c:M:N:w:")) != EOF) |
d3f8ef0e KB |
115 | switch(ch) { |
116 | case 'c': | |
117 | reps = atoi(optarg); | |
118 | break; | |
114fa233 | 119 | case 'M': |
ad07e3a9 | 120 | memf = optarg; |
114fa233 KB |
121 | break; |
122 | case 'N': | |
ad07e3a9 | 123 | nlistf = optarg; |
114fa233 | 124 | break; |
3cead284 KB |
125 | case 'w': |
126 | interval = atoi(optarg); | |
127 | break; | |
d3f8ef0e KB |
128 | case '?': |
129 | default: | |
130 | usage(); | |
131 | } | |
132 | argc -= optind; | |
133 | argv += optind; | |
be974f30 | 134 | |
ad07e3a9 KB |
135 | /* |
136 | * Discard setgid privileges if not the running kernel so that bad | |
137 | * guys can't print interesting stuff from kernel memory. | |
138 | */ | |
139 | if (nlistf != NULL || memf != NULL) | |
140 | setgid(getgid()); | |
141 | ||
100709ca SM |
142 | kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf); |
143 | if (kd == 0) | |
144 | err("kvm_openfiles: %s", errbuf); | |
145 | if (kvm_nlist(kd, nl) == -1) | |
146 | err("kvm_nlist: %s", kvm_geterr(kd)); | |
703187b4 KB |
147 | if (nl[X_DK_NDRIVE].n_type == 0) |
148 | err("dk_ndrive not found in namelist"); | |
114fa233 | 149 | (void)nlread(X_DK_NDRIVE, dk_ndrive); |
703187b4 KB |
150 | if (dk_ndrive <= 0) |
151 | err("invalid dk_ndrive %d\n", dk_ndrive); | |
d3f8ef0e | 152 | |
114fa233 KB |
153 | cur.dk_time = calloc(dk_ndrive, sizeof(long)); |
154 | cur.dk_wds = calloc(dk_ndrive, sizeof(long)); | |
155 | cur.dk_seek = calloc(dk_ndrive, sizeof(long)); | |
156 | cur.dk_xfer = calloc(dk_ndrive, sizeof(long)); | |
157 | last.dk_time = calloc(dk_ndrive, sizeof(long)); | |
158 | last.dk_wds = calloc(dk_ndrive, sizeof(long)); | |
159 | last.dk_seek = calloc(dk_ndrive, sizeof(long)); | |
160 | last.dk_xfer = calloc(dk_ndrive, sizeof(long)); | |
d3f8ef0e KB |
161 | dr_select = calloc(dk_ndrive, sizeof(int)); |
162 | dr_name = calloc(dk_ndrive, sizeof(char *)); | |
163 | dk_wpms = calloc(dk_ndrive, sizeof(long)); | |
164 | ||
3cead284 KB |
165 | for (i = 0; i < dk_ndrive; i++) { |
166 | (void)sprintf(buf, "dk%d", i); | |
167 | dr_name[i] = strdup(buf); | |
94f8dc1b | 168 | } |
131d8dcb KB |
169 | if (!read_names()) |
170 | exit(1); | |
114fa233 | 171 | (void)nlread(X_HZ, hz); |
100709ca SM |
172 | (void)nlread(X_STATHZ, stathz); |
173 | if (stathz) | |
174 | hz = stathz; | |
175 | (void)kvm_read(kd, nl[X_DK_WPMS].n_value, dk_wpms, | |
114fa233 | 176 | dk_ndrive * sizeof(dk_wpms)); |
d3f8ef0e | 177 | |
94f8dc1b | 178 | /* |
d3f8ef0e KB |
179 | * Choose drives to be displayed. Priority goes to (in order) drives |
180 | * supplied as arguments and default drives. If everything isn't | |
181 | * filled in and there are drives not taken care of, display the first | |
182 | * few that fit. | |
cc91baf1 KB |
183 | * |
184 | * The backward compatibility #ifdefs permit the syntax: | |
185 | * iostat [ drives ] [ interval [ count ] ] | |
94f8dc1b | 186 | */ |
cc91baf1 KB |
187 | #define BACKWARD_COMPATIBILITY |
188 | for (ndrives = 0; *argv; ++argv) { | |
189 | #ifdef BACKWARD_COMPATIBILITY | |
190 | if (isdigit(**argv)) | |
191 | break; | |
192 | #endif | |
94f8dc1b | 193 | for (i = 0; i < dk_ndrive; i++) { |
d3f8ef0e | 194 | if (strcmp(dr_name[i], *argv)) |
94f8dc1b SL |
195 | continue; |
196 | dr_select[i] = 1; | |
d3f8ef0e | 197 | ++ndrives; |
94f8dc1b | 198 | } |
cc91baf1 KB |
199 | } |
200 | #ifdef BACKWARD_COMPATIBILITY | |
201 | if (*argv) { | |
202 | interval = atoi(*argv); | |
203 | if (*++argv) | |
204 | reps = atoi(*argv); | |
205 | } | |
206 | #endif | |
f2f79253 KB |
207 | |
208 | if (interval) { | |
209 | if (!reps) | |
210 | reps = -1; | |
211 | } else | |
212 | if (reps) | |
213 | interval = 1; | |
214 | ||
94f8dc1b | 215 | for (i = 0; i < dk_ndrive && ndrives < 4; i++) { |
b02d33b6 | 216 | if (dr_select[i] || dk_wpms[i] == 0) |
94f8dc1b SL |
217 | continue; |
218 | for (cp = defdrives; *cp; cp++) | |
219 | if (strcmp(dr_name[i], *cp) == 0) { | |
220 | dr_select[i] = 1; | |
d3f8ef0e | 221 | ++ndrives; |
94f8dc1b SL |
222 | break; |
223 | } | |
224 | } | |
225 | for (i = 0; i < dk_ndrive && ndrives < 4; i++) { | |
226 | if (dr_select[i]) | |
227 | continue; | |
228 | dr_select[i] = 1; | |
d3f8ef0e | 229 | ++ndrives; |
94f8dc1b | 230 | } |
d3f8ef0e | 231 | |
9835199b | 232 | (void)signal(SIGCONT, phdr); |
d3f8ef0e KB |
233 | |
234 | for (hdrcnt = 1;;) { | |
235 | if (!--hdrcnt) { | |
703187b4 | 236 | phdr(0); |
d3f8ef0e KB |
237 | hdrcnt = 20; |
238 | } | |
100709ca | 239 | (void)kvm_read(kd, nl[X_DK_TIME].n_value, |
114fa233 | 240 | cur.dk_time, dk_ndrive * sizeof(long)); |
100709ca | 241 | (void)kvm_read(kd, nl[X_DK_XFER].n_value, |
114fa233 | 242 | cur.dk_xfer, dk_ndrive * sizeof(long)); |
100709ca | 243 | (void)kvm_read(kd, nl[X_DK_WDS].n_value, |
114fa233 | 244 | cur.dk_wds, dk_ndrive * sizeof(long)); |
100709ca | 245 | (void)kvm_read(kd, nl[X_DK_SEEK].n_value, |
114fa233 | 246 | cur.dk_seek, dk_ndrive * sizeof(long)); |
100709ca | 247 | (void)kvm_read(kd, nl[X_TK_NIN].n_value, |
114fa233 | 248 | &cur.tk_nin, sizeof(cur.tk_nin)); |
100709ca | 249 | (void)kvm_read(kd, nl[X_TK_NOUT].n_value, |
114fa233 | 250 | &cur.tk_nout, sizeof(cur.tk_nout)); |
100709ca | 251 | (void)kvm_read(kd, nl[X_CP_TIME].n_value, |
114fa233 | 252 | cur.cp_time, sizeof(cur.cp_time)); |
d3f8ef0e KB |
253 | for (i = 0; i < dk_ndrive; i++) { |
254 | if (!dr_select[i]) | |
255 | continue; | |
114fa233 | 256 | #define X(fld) tmp = cur.fld[i]; cur.fld[i] -= last.fld[i]; last.fld[i] = tmp |
d3f8ef0e KB |
257 | X(dk_xfer); |
258 | X(dk_seek); | |
259 | X(dk_wds); | |
260 | X(dk_time); | |
261 | } | |
114fa233 KB |
262 | tmp = cur.tk_nin; |
263 | cur.tk_nin -= last.tk_nin; | |
264 | last.tk_nin = tmp; | |
265 | tmp = cur.tk_nout; | |
266 | cur.tk_nout -= last.tk_nout; | |
267 | last.tk_nout = tmp; | |
d3f8ef0e KB |
268 | etime = 0; |
269 | for (i = 0; i < CPUSTATES; i++) { | |
270 | X(cp_time); | |
114fa233 | 271 | etime += cur.cp_time[i]; |
d3f8ef0e KB |
272 | } |
273 | if (etime == 0.0) | |
274 | etime = 1.0; | |
114fa233 KB |
275 | etime /= (float)hz; |
276 | (void)printf("%4.0f%5.0f", | |
277 | cur.tk_nin / etime, cur.tk_nout / etime); | |
703187b4 KB |
278 | dkstats(); |
279 | cpustats(); | |
d3f8ef0e KB |
280 | (void)printf("\n"); |
281 | (void)fflush(stdout); | |
282 | ||
f2f79253 | 283 | if (reps >= 0 && --reps <= 0) |
d3f8ef0e | 284 | break; |
f94a0025 | 285 | (void)sleep(interval); |
be974f30 | 286 | } |
d3f8ef0e | 287 | exit(0); |
be974f30 BJ |
288 | } |
289 | ||
703187b4 | 290 | /* ARGUSED */ |
d3f8ef0e | 291 | void |
703187b4 KB |
292 | phdr(notused) |
293 | int notused; | |
94f8dc1b SL |
294 | { |
295 | register int i; | |
296 | ||
d3f8ef0e | 297 | (void)printf(" tty"); |
94f8dc1b SL |
298 | for (i = 0; i < dk_ndrive; i++) |
299 | if (dr_select[i]) | |
d3f8ef0e KB |
300 | (void)printf(" %3.3s ", dr_name[i]); |
301 | (void)printf(" cpu\n tin tout"); | |
94f8dc1b SL |
302 | for (i = 0; i < dk_ndrive; i++) |
303 | if (dr_select[i]) | |
9835199b | 304 | (void)printf(" sps tps msps "); |
d3f8ef0e | 305 | (void)printf(" us ni sy id\n"); |
94f8dc1b SL |
306 | } |
307 | ||
d3f8ef0e | 308 | void |
9835199b | 309 | dkstats() |
be974f30 | 310 | { |
9835199b KB |
311 | register int dn; |
312 | double atime, itime, msps, words, xtime; | |
be974f30 | 313 | |
9835199b KB |
314 | for (dn = 0; dn < dk_ndrive; ++dn) { |
315 | if (!dr_select[dn]) | |
316 | continue; | |
317 | words = cur.dk_wds[dn] * 32; /* words xfer'd */ | |
318 | (void)printf("%4.0f", /* sectors */ | |
319 | words / (DEV_BSIZE / 2) / etime); | |
320 | ||
321 | (void)printf("%4.0f", cur.dk_xfer[dn] / etime); | |
322 | ||
323 | if (dk_wpms[dn] && cur.dk_xfer[dn]) { | |
324 | atime = cur.dk_time[dn]; /* ticks disk busy */ | |
325 | atime /= (float)hz; /* ticks to seconds */ | |
326 | xtime = words / dk_wpms[dn]; /* transfer time */ | |
327 | itime = atime - xtime; /* time not xfer'ing */ | |
328 | if (itime < 0) | |
329 | msps = 0; | |
330 | else | |
331 | msps = itime * 1000 / cur.dk_xfer[dn]; | |
332 | } else | |
333 | msps = 0; | |
334 | (void)printf("%5.1f ", msps); | |
be974f30 | 335 | } |
be974f30 BJ |
336 | } |
337 | ||
d3f8ef0e | 338 | void |
9835199b | 339 | cpustats() |
be974f30 | 340 | { |
9835199b | 341 | register int state; |
be974f30 BJ |
342 | double time; |
343 | ||
344 | time = 0; | |
9835199b KB |
345 | for (state = 0; state < CPUSTATES; ++state) |
346 | time += cur.cp_time[state]; | |
347 | for (state = 0; state < CPUSTATES; ++state) | |
348 | (void)printf("%3.0f", | |
349 | 100. * cur.cp_time[state] / (time ? time : 1)); | |
be974f30 | 350 | } |
700789be | 351 | |
d3f8ef0e KB |
352 | void |
353 | usage() | |
354 | { | |
355 | (void)fprintf(stderr, | |
3cead284 | 356 | "usage: iostat [-c count] [-M core] [-N system] [-w wait] [drives]\n"); |
d3f8ef0e KB |
357 | exit(1); |
358 | } | |
359 | ||
703187b4 KB |
360 | #if __STDC__ |
361 | #include <stdarg.h> | |
362 | #else | |
363 | #include <varargs.h> | |
364 | #endif | |
365 | ||
d3f8ef0e | 366 | void |
703187b4 KB |
367 | #if __STDC__ |
368 | err(const char *fmt, ...) | |
369 | #else | |
370 | err(fmt, va_alist) | |
114fa233 | 371 | char *fmt; |
703187b4 KB |
372 | va_dcl |
373 | #endif | |
700789be | 374 | { |
114fa233 | 375 | va_list ap; |
703187b4 KB |
376 | #if __STDC__ |
377 | va_start(ap, fmt); | |
378 | #else | |
379 | va_start(ap); | |
380 | #endif | |
381 | (void)fprintf(stderr, "iostat: "); | |
382 | (void)vfprintf(stderr, fmt, ap); | |
383 | va_end(ap); | |
384 | (void)fprintf(stderr, "\n"); | |
385 | exit(1); | |
386 | /* NOTREACHED */ | |
b0c469a3 | 387 | } |