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