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