iostat.c revision 1.6 1 /*-
2 * Copyright (c) 1986, 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #ifndef lint
35 static char copyright[] =
36 "@(#) Copyright (c) 1986, 1991, 1993\n\
37 The Regents of the University of California. All rights reserved.\n";
38 #endif /* not lint */
39
40 #ifndef lint
41 /* from: static char sccsid[] = "@(#)iostat.c 8.2 (Berkeley) 1/26/94"; */
42 static char *rcsid = "$Id: iostat.c,v 1.6 1994/05/14 21:52:22 cgd Exp $";
43 #endif /* not lint */
44
45 #include <sys/param.h>
46 #include <sys/buf.h>
47 #include <sys/dkstat.h>
48
49 #include <err.h>
50 #include <ctype.h>
51 #include <fcntl.h>
52 #include <kvm.h>
53 #include <limits.h>
54 #include <nlist.h>
55 #include <paths.h>
56 #include <signal.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #include <unistd.h>
61
62 struct nlist namelist[] = {
63 #define X_DK_TIME 0
64 { "_dk_time" },
65 #define X_DK_XFER 1
66 { "_dk_xfer" },
67 #define X_DK_WDS 2
68 { "_dk_wds" },
69 #define X_TK_NIN 3
70 { "_tk_nin" },
71 #define X_TK_NOUT 4
72 { "_tk_nout" },
73 #define X_DK_SEEK 5
74 { "_dk_seek" },
75 #define X_CP_TIME 6
76 { "_cp_time" },
77 #define X_DK_WPMS 7
78 { "_dk_wpms" },
79 #define X_HZ 8
80 { "_hz" },
81 #define X_STATHZ 9
82 { "_stathz" },
83 #define X_DK_NDRIVE 10
84 { "_dk_ndrive" },
85 #define X_END 10
86 #if defined(hp300) || defined(luna68k)
87 #define X_HPDINIT (X_END+1)
88 { "_hp_dinit" },
89 #endif
90 #ifdef mips
91 #define X_SCSI_DINIT (X_END+1)
92 { "_scsi_dinit" },
93 #endif
94 #ifdef tahoe
95 #define X_VBDINIT (X_END+1)
96 { "_vbdinit" },
97 #endif
98 #ifdef vax
99 { "_mbdinit" },
100 #define X_MBDINIT (X_END+1)
101 { "_ubdinit" },
102 #define X_UBDINIT (X_END+2)
103 #endif
104 { NULL },
105 };
106
107 struct _disk {
108 long cp_time[CPUSTATES];
109 long *dk_time;
110 long *dk_wds;
111 long *dk_seek;
112 long *dk_xfer;
113 long tk_nin;
114 long tk_nout;
115 } cur, last;
116
117 kvm_t *kd;
118 double etime;
119 long *dk_wpms;
120 int dk_ndrive, *dr_select, hz, kmemfd, ndrives;
121 char **dr_name;
122
123 #define nlread(x, v) \
124 kvm_read(kd, namelist[x].n_value, &(v), sizeof(v))
125
126 #include "names.c" /* XXX */
127
128 void cpustats __P((void));
129 void dkstats __P((void));
130 void phdr __P((int));
131 void usage __P((void));
132
133 int
134 main(argc, argv)
135 int argc;
136 char *argv[];
137 {
138 register int i;
139 long tmp;
140 int ch, hdrcnt, reps, interval, stathz, ndrives;
141 char **cp, *memf, *nlistf, buf[30];
142 char errbuf[_POSIX2_LINE_MAX];
143
144 interval = reps = 0;
145 nlistf = memf = NULL;
146 while ((ch = getopt(argc, argv, "c:M:N:w:")) != EOF)
147 switch(ch) {
148 case 'c':
149 if ((reps = atoi(optarg)) <= 0)
150 errx(1, "repetition count <= 0.");
151 break;
152 case 'M':
153 memf = optarg;
154 break;
155 case 'N':
156 nlistf = optarg;
157 break;
158 case 'w':
159 if ((interval = atoi(optarg)) <= 0)
160 errx(1, "interval <= 0.");
161 break;
162 case '?':
163 default:
164 usage();
165 }
166 argc -= optind;
167 argv += optind;
168
169 /*
170 * Discard setgid privileges if not the running kernel so that bad
171 * guys can't print interesting stuff from kernel memory.
172 */
173 if (nlistf != NULL || memf != NULL)
174 setgid(getgid());
175
176 kd = kvm_openfiles(nlistf, memf, NULL, O_RDONLY, errbuf);
177 if (kd == 0)
178 errx(1, "kvm_openfiles: %s", errbuf);
179 if (kvm_nlist(kd, namelist) == -1)
180 errx(1, "kvm_nlist: %s", kvm_geterr(kd));
181 if (namelist[X_DK_NDRIVE].n_type == 0)
182 errx(1, "dk_ndrive not found in namelist");
183 (void)nlread(X_DK_NDRIVE, dk_ndrive);
184 if (dk_ndrive <= 0)
185 errx(1, "invalid dk_ndrive %d\n", dk_ndrive);
186
187 cur.dk_time = calloc(dk_ndrive, sizeof(long));
188 cur.dk_wds = calloc(dk_ndrive, sizeof(long));
189 cur.dk_seek = calloc(dk_ndrive, sizeof(long));
190 cur.dk_xfer = calloc(dk_ndrive, sizeof(long));
191 last.dk_time = calloc(dk_ndrive, sizeof(long));
192 last.dk_wds = calloc(dk_ndrive, sizeof(long));
193 last.dk_seek = calloc(dk_ndrive, sizeof(long));
194 last.dk_xfer = calloc(dk_ndrive, sizeof(long));
195 dr_select = calloc(dk_ndrive, sizeof(int));
196 dr_name = calloc(dk_ndrive, sizeof(char *));
197 dk_wpms = calloc(dk_ndrive, sizeof(long));
198
199 for (i = 0; i < dk_ndrive; i++) {
200 (void)sprintf(buf, "dk%d", i);
201 dr_name[i] = strdup(buf);
202 }
203 if (!read_names())
204 exit(1);
205 (void)nlread(X_HZ, hz);
206 (void)nlread(X_STATHZ, stathz);
207 if (stathz)
208 hz = stathz;
209 (void)kvm_read(kd, namelist[X_DK_WPMS].n_value, dk_wpms,
210 dk_ndrive * sizeof(dk_wpms));
211
212 /*
213 * Choose drives to be displayed. Priority goes to (in order) drives
214 * supplied as arguments and default drives. If everything isn't
215 * filled in and there are drives not taken care of, display the first
216 * few that fit.
217 *
218 * The backward compatibility #ifdefs permit the syntax:
219 * iostat [ drives ] [ interval [ count ] ]
220 */
221 #define BACKWARD_COMPATIBILITY
222 for (ndrives = 0; *argv; ++argv) {
223 #ifdef BACKWARD_COMPATIBILITY
224 if (isdigit(**argv))
225 break;
226 #endif
227 for (i = 0; i < dk_ndrive; i++) {
228 if (strcmp(dr_name[i], *argv))
229 continue;
230 dr_select[i] = 1;
231 ++ndrives;
232 }
233 }
234 #ifdef BACKWARD_COMPATIBILITY
235 if (*argv) {
236 interval = atoi(*argv);
237 if (*++argv)
238 reps = atoi(*argv);
239 }
240 #endif
241
242 if (interval) {
243 if (!reps)
244 reps = -1;
245 } else
246 if (reps)
247 interval = 1;
248
249 for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
250 if (dr_select[i] || dk_wpms[i] == 0)
251 continue;
252 for (cp = defdrives; *cp; cp++)
253 if (strcmp(dr_name[i], *cp) == 0) {
254 dr_select[i] = 1;
255 ++ndrives;
256 break;
257 }
258 }
259 for (i = 0; i < dk_ndrive && ndrives < 4; i++) {
260 if (dr_select[i])
261 continue;
262 dr_select[i] = 1;
263 ++ndrives;
264 }
265
266 (void)signal(SIGCONT, phdr);
267
268 for (hdrcnt = 1;;) {
269 if (!--hdrcnt) {
270 phdr(0);
271 hdrcnt = 20;
272 }
273 (void)kvm_read(kd, namelist[X_DK_TIME].n_value,
274 cur.dk_time, dk_ndrive * sizeof(long));
275 (void)kvm_read(kd, namelist[X_DK_XFER].n_value,
276 cur.dk_xfer, dk_ndrive * sizeof(long));
277 (void)kvm_read(kd, namelist[X_DK_WDS].n_value,
278 cur.dk_wds, dk_ndrive * sizeof(long));
279 (void)kvm_read(kd, namelist[X_DK_SEEK].n_value,
280 cur.dk_seek, dk_ndrive * sizeof(long));
281 (void)kvm_read(kd, namelist[X_TK_NIN].n_value,
282 &cur.tk_nin, sizeof(cur.tk_nin));
283 (void)kvm_read(kd, namelist[X_TK_NOUT].n_value,
284 &cur.tk_nout, sizeof(cur.tk_nout));
285 (void)kvm_read(kd, namelist[X_CP_TIME].n_value,
286 cur.cp_time, sizeof(cur.cp_time));
287 for (i = 0; i < dk_ndrive; i++) {
288 if (!dr_select[i])
289 continue;
290 #define X(fld) tmp = cur.fld[i]; cur.fld[i] -= last.fld[i]; last.fld[i] = tmp
291 X(dk_xfer);
292 X(dk_seek);
293 X(dk_wds);
294 X(dk_time);
295 }
296 tmp = cur.tk_nin;
297 cur.tk_nin -= last.tk_nin;
298 last.tk_nin = tmp;
299 tmp = cur.tk_nout;
300 cur.tk_nout -= last.tk_nout;
301 last.tk_nout = tmp;
302 etime = 0;
303 for (i = 0; i < CPUSTATES; i++) {
304 X(cp_time);
305 etime += cur.cp_time[i];
306 }
307 if (etime == 0.0)
308 etime = 1.0;
309 etime /= (float)hz;
310 (void)printf("%4.0f%5.0f",
311 cur.tk_nin / etime, cur.tk_nout / etime);
312 dkstats();
313 cpustats();
314 (void)printf("\n");
315 (void)fflush(stdout);
316
317 if (reps >= 0 && --reps <= 0)
318 break;
319 (void)sleep(interval);
320 }
321 exit(0);
322 }
323
324 /* ARGUSED */
325 void
326 phdr(signo)
327 int signo;
328 {
329 register int i;
330
331 (void)printf(" tty");
332 for (i = 0; i < dk_ndrive; i++)
333 if (dr_select[i])
334 (void)printf(" %3.3s ", dr_name[i]);
335 (void)printf(" cpu\n tin tout");
336 for (i = 0; i < dk_ndrive; i++)
337 if (dr_select[i])
338 (void)printf(" sps tps msps ");
339 (void)printf(" us ni sy id\n");
340 }
341
342 void
343 dkstats()
344 {
345 register int dn;
346 double atime, itime, msps, words, xtime;
347
348 for (dn = 0; dn < dk_ndrive; ++dn) {
349 if (!dr_select[dn])
350 continue;
351 words = cur.dk_wds[dn] * 32; /* words xfer'd */
352 (void)printf("%4.0f", /* sectors */
353 words / (DEV_BSIZE / 2) / etime);
354
355 (void)printf("%4.0f", cur.dk_xfer[dn] / etime);
356
357 if (dk_wpms[dn] && cur.dk_xfer[dn]) {
358 atime = cur.dk_time[dn]; /* ticks disk busy */
359 atime /= (float)hz; /* ticks to seconds */
360 xtime = words / dk_wpms[dn]; /* transfer time */
361 itime = atime - xtime; /* time not xfer'ing */
362 if (itime < 0)
363 msps = 0;
364 else
365 msps = itime * 1000 / cur.dk_xfer[dn];
366 } else
367 msps = 0;
368 (void)printf("%5.1f ", msps);
369 }
370 }
371
372 void
373 cpustats()
374 {
375 register int state;
376 double time;
377
378 time = 0;
379 for (state = 0; state < CPUSTATES; ++state)
380 time += cur.cp_time[state];
381 for (state = 0; state < CPUSTATES; ++state)
382 (void)printf("%3.0f",
383 100. * cur.cp_time[state] / (time ? time : 1));
384 }
385
386 void
387 usage()
388 {
389 (void)fprintf(stderr,
390 "usage: iostat [-c count] [-M core] [-N system] [-w wait] [drives]\n");
391 exit(1);
392 }
393