1 /* $NetBSD: iostat.c,v 1.52 2008/07/21 13:36:58 lukem Exp $ */
4 * Copyright (c) 1996 John M. Vinopal
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed for the NetBSD Project
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * Copyright (c) 1986, 1991, 1993
37 * The Regents of the University of California. All rights reserved.
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions
42 * 1. Redistributions of source code must retain the above copyright
43 * notice, this list of conditions and the following disclaimer.
44 * 2. Redistributions in binary form must reproduce the above copyright
45 * notice, this list of conditions and the following disclaimer in the
46 * documentation and/or other materials provided with the distribution.
47 * 3. Neither the name of the University nor the names of its contributors
48 * may be used to endorse or promote products derived from this software
49 * without specific prior written permission.
51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64 #include <sys/cdefs.h>
66 __COPYRIGHT("@(#) Copyright (c) 1986, 1991, 1993\
67 The Regents of the University of California. All rights reserved.");
72 static char sccsid
[] = "@(#)iostat.c 8.3 (Berkeley) 4/28/95";
74 __RCSID("$NetBSD: iostat.c,v 1.52 2008/07/21 13:36:58 lukem Exp $");
78 #include <sys/types.h>
79 #include <sys/ioctl.h>
80 #include <sys/sched.h>
93 /* Namelist and memory files. */
96 int hz
, reps
, interval
;
99 static int winlines
= 20;
100 static int wincols
= 80;
102 #define ISSET(x, a) ((x) & (a))
103 #define SHOW_CPU (1<<0)
104 #define SHOW_TTY (1<<1)
105 #define SHOW_STATS_1 (1<<2)
106 #define SHOW_STATS_2 (1<<3)
107 #define SHOW_STATS_X (1<<4)
108 #define SHOW_TOTALS (1<<7)
109 #define SHOW_STATS_ALL (SHOW_STATS_1 | SHOW_STATS_2 | SHOW_STATS_X)
111 static void cpustats(void);
112 static void drive_stats(double);
113 static void drive_stats2(double);
114 static void drive_statsx(double);
115 static void sig_header(int);
116 static volatile int do_header
;
117 static void header(void);
118 static void usage(void);
119 static void display(void);
120 static int selectdrives(int, char *[]);
122 int main(int, char *[]);
125 main(int argc
, char *argv
[])
127 int ch
, hdrcnt
, ndrives
, lines
;
131 while ((ch
= getopt(argc
, argv
, "Cc:dDIM:N:Tw:x")) != -1)
134 if ((reps
= atoi(optarg
)) <= 0)
135 errx(1, "repetition count <= 0.");
141 todo
&= ~SHOW_STATS_ALL
;
142 todo
|= SHOW_STATS_1
;
145 todo
&= ~SHOW_STATS_ALL
;
146 todo
|= SHOW_STATS_2
;
161 if ((interval
= atoi(optarg
)) <= 0)
162 errx(1, "interval <= 0.");
165 todo
&= ~SHOW_STATS_ALL
;
166 todo
|= SHOW_STATS_X
;
175 if (!ISSET(todo
, SHOW_CPU
| SHOW_TTY
| SHOW_STATS_ALL
))
176 todo
|= SHOW_CPU
| SHOW_TTY
| SHOW_STATS_1
;
177 if (ISSET(todo
, SHOW_STATS_X
)) {
178 todo
&= ~(SHOW_CPU
| SHOW_TTY
| SHOW_STATS_ALL
);
179 todo
|= SHOW_STATS_X
;
182 if (ioctl(STDOUT_FILENO
, TIOCGSIZE
, &ts
) != -1) {
184 winlines
= ts
.ts_lines
;
186 wincols
= ts
.ts_cols
;
190 if (ISSET(todo
, SHOW_CPU
))
191 defdrives
-= 16; /* XXX magic number */
192 if (ISSET(todo
, SHOW_TTY
))
193 defdrives
-= 9; /* XXX magic number */
194 defdrives
/= 18; /* XXX magic number */
199 ndrives
= selectdrives(argc
, argv
);
201 /* No drives are selected. No need to show drive stats. */
202 todo
&= ~SHOW_STATS_ALL
;
204 errx(1, "no drives");
206 if (ISSET(todo
, SHOW_STATS_X
))
211 tv
.tv_sec
= interval
;
214 /* print a new header on sigcont */
215 (void)signal(SIGCONT
, sig_header
);
218 if (do_header
|| lines
> 1 || (hdrcnt
-= lines
) <= 0) {
221 hdrcnt
= winlines
- 4;
224 if (!ISSET(todo
, SHOW_TOTALS
)) {
232 if (reps
>= 0 && --reps
<= 0)
234 nanosleep(&tv
, NULL
);
242 sig_header(int signo
)
253 if (ISSET(todo
, SHOW_STATS_X
)) {
254 if (ISSET(todo
, SHOW_TOTALS
)) {
256 "device read KB/t xfr time MB ");
257 (void)printf(" write KB/t xfr time MB\n");
260 "device read KB/t r/s time MB/s");
261 (void)printf(" write KB/t w/s time MB/s\n");
266 if (ISSET(todo
, SHOW_TTY
))
267 (void)printf(" tty");
269 if (ISSET(todo
, SHOW_STATS_1
)) {
270 for (i
= 0; i
< ndrive
; i
++)
272 (void)printf(" %9.9s ", cur
.name
[i
]);
275 if (ISSET(todo
, SHOW_STATS_2
)) {
276 for (i
= 0; i
< ndrive
; i
++)
278 (void)printf(" %9.9s ", cur
.name
[i
]);
281 if (ISSET(todo
, SHOW_CPU
))
282 (void)printf(" CPU");
287 if (ISSET(todo
, SHOW_TTY
))
290 if (ISSET(todo
, SHOW_STATS_1
)) {
291 for (i
= 0; i
< ndrive
; i
++)
293 if (ISSET(todo
, SHOW_TOTALS
))
294 (void)printf(" KB/t xfr MB ");
296 (void)printf(" KB/t t/s MB/s ");
300 if (ISSET(todo
, SHOW_STATS_2
)) {
301 for (i
= 0; i
< ndrive
; i
++)
303 (void)printf(" KB xfr time ");
306 if (ISSET(todo
, SHOW_CPU
))
307 (void)printf(" us ni sy in id");
312 drive_stats(double etime
)
317 for (dn
= 0; dn
< ndrive
; ++dn
) {
320 /* average Kbytes per transfer. */
321 if (cur
.rxfer
[dn
] + cur
.wxfer
[dn
])
322 mbps
= ((cur
.rbytes
[dn
] + cur
.wbytes
[dn
]) /
323 1024.0) / (cur
.rxfer
[dn
] + cur
.wxfer
[dn
]);
326 (void)printf(" %5.2f", mbps
);
328 /* average transfers per second. */
329 (void)printf(" %4.0f",
330 (cur
.rxfer
[dn
] + cur
.wxfer
[dn
]) / etime
);
332 /* time busy in drive activity */
333 atime
= (double)cur
.time
[dn
].tv_sec
+
334 ((double)cur
.time
[dn
].tv_usec
/ (double)1000000);
336 /* Megabytes per second. */
338 mbps
= (cur
.rbytes
[dn
] + cur
.wbytes
[dn
]) /
339 (double)(1024 * 1024);
342 (void)printf(" %5.2f ", mbps
/ etime
);
347 drive_stats2(double etime
)
352 for (dn
= 0; dn
< ndrive
; ++dn
) {
356 /* average kbytes per second. */
357 (void)printf(" %5.0f",
358 (cur
.rbytes
[dn
] + cur
.wbytes
[dn
]) / 1024.0 / etime
);
360 /* average transfers per second. */
361 (void)printf(" %5.0f",
362 (cur
.rxfer
[dn
] + cur
.wxfer
[dn
]) / etime
);
364 /* average time busy in drive activity */
365 atime
= (double)cur
.time
[dn
].tv_sec
+
366 ((double)cur
.time
[dn
].tv_usec
/ (double)1000000);
367 (void)printf(" %4.2f ", atime
/ etime
);
372 drive_statsx(double etime
)
377 for (dn
= 0; dn
< ndrive
; ++dn
) {
381 (void)printf("%-8.8s", cur
.name
[dn
]);
383 /* average read Kbytes per transfer */
385 kbps
= (cur
.rbytes
[dn
] / 1024.0) / cur
.rxfer
[dn
];
388 (void)printf(" %8.2f", kbps
);
390 /* average read transfers
392 (void)printf(" %6.0f", cur
.rxfer
[dn
] / etime
);
394 /* time read busy in drive activity */
395 atime
= (double)cur
.time
[dn
].tv_sec
+
396 ((double)cur
.time
[dn
].tv_usec
/ (double)1000000);
397 (void)printf(" %6.2f", atime
/ etime
);
399 /* average read megabytes
401 (void)printf(" %8.2f",
402 cur
.rbytes
[dn
] / (1024.0 * 1024) / etime
);
405 /* average write Kbytes per transfer */
407 kbps
= (cur
.wbytes
[dn
] / 1024.0) / cur
.wxfer
[dn
];
410 (void)printf(" %8.2f", kbps
);
412 /* average write transfers
414 (void)printf(" %6.0f", cur
.wxfer
[dn
] / etime
);
416 /* time write busy in drive activity */
417 atime
= (double)cur
.time
[dn
].tv_sec
+
418 ((double)cur
.time
[dn
].tv_usec
/ (double)1000000);
419 (void)printf(" %6.2f", atime
/ etime
);
421 /* average write megabytes
423 (void)printf(" %8.2f\n",
424 cur
.wbytes
[dn
] / (1024.0 * 1024) / etime
);
435 for (state
= 0; state
< CPUSTATES
; ++state
)
436 ttime
+= cur
.cp_time
[state
];
439 /* States are generally never 100% and can use %3.0f. */
440 for (state
= 0; state
< CPUSTATES
; ++state
)
441 printf(" %2.0f", 100. * cur
.cp_time
[state
] / ttime
);
448 (void)fprintf(stderr
, "usage: iostat [-CdDITx] [-c count] [-M core] "
449 "[-N system] [-w wait] [drives]\n");
458 /* Sum up the elapsed ticks. */
459 etime
= cur
.cp_etime
;
462 * If we're showing totals only, then don't divide by the
465 if (ISSET(todo
, SHOW_TOTALS
))
468 if (ISSET(todo
, SHOW_STATS_X
)) {
473 if (ISSET(todo
, SHOW_TTY
))
474 printf("%4.0f %4.0f", cur
.tk_nin
/ etime
, cur
.tk_nout
/ etime
);
476 if (ISSET(todo
, SHOW_STATS_1
)) {
481 if (ISSET(todo
, SHOW_STATS_2
)) {
486 if (ISSET(todo
, SHOW_CPU
))
492 (void)fflush(stdout
);
496 selectdrives(int argc
, char *argv
[])
498 int i
, maxdrives
, ndrives
, tried
;
501 * Choose drives to be displayed. Priority goes to (in order) drives
502 * supplied as arguments and default drives. If everything isn't
503 * filled in and there are drives not taken care of, display the first
506 * The backward compatibility #ifdefs permit the syntax:
507 * iostat [ drives ] [ interval [ count ] ]
510 #define BACKWARD_COMPATIBILITY
511 for (tried
= ndrives
= 0; *argv
; ++argv
) {
512 #ifdef BACKWARD_COMPATIBILITY
513 if (isdigit((unsigned char)**argv
))
517 for (i
= 0; i
< (int)ndrive
; i
++) {
518 if (strcmp(cur
.name
[i
], *argv
))
526 if (ndrives
== 0 && tried
== 0) {
528 * Pick up to defdrives (or all if -x is given) drives
531 maxdrives
= (ISSET(todo
, SHOW_STATS_X
) ||
532 (int)ndrive
< defdrives
)
533 ? (int)(ndrive
) : defdrives
;
534 for (i
= 0; i
< maxdrives
; i
++) {
538 if (!ISSET(todo
, SHOW_STATS_X
) && ndrives
== defdrives
)
543 #ifdef BACKWARD_COMPATIBILITY
545 interval
= atoi(*argv
);