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