bin/68840: [PATCH] Add Solaris-style -x flag to iostat
Dan Nelson
dnelson at allantgroup.com
Thu Jul 8 20:00:43 PDT 2004
>Number: 68840
>Category: bin
>Synopsis: [PATCH] Add Solaris-style -x flag to iostat
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: change-request
>Submitter-Id: current-users
>Arrival-Date: Fri Jul 09 03:00:41 GMT 2004
>Closed-Date:
>Last-Modified:
>Originator: Dan Nelson
>Release: FreeBSD 5.2-CURRENT i386
>Organization:
The Allant Group
>Environment:
System: FreeBSD dan.emsphone.com 5.2-CURRENT FreeBSD 5.2-CURRENT #341: Wed Jun 23 23:03:45 CDT 2004 zsh at dan.emsphone.com:/usr/src/sys/i386/compile/DANSMP i386
>Description:
I really like Solaris's extended device stats mode in iostat. It
splits read and write stats and provides %busy and queued IO columns.
>How-To-Repeat:
>Fix:
The "wait" and "%w" columns are currently empty because there's no way
to ask the system how many of the queued I/O operations are being
processed by the disk and how many are still in the kernel. On IDE/ATA
disks, "wait" would always be "actv"-1, and on a SCSI system, wait
would be nonzero when the number of active commands exceeded the disks
tagged queue limit.
$ iostat -zxC 1
extended device statistics cpu
device r/s w/s kr/s kw/s wait actv svc_t %w %b us ni sy in id
da0 0.0 179.2 0.0 903.9 0 71 344.3 0 78 0 0 7 2 91
extended device statistics cpu
device r/s w/s kr/s kw/s wait actv svc_t %w %b us ni sy in id
da0 0.0 149.5 0.0 3372.1 0 49 504.9 0 100 1 3 26 2 69
It's more impressive with more disks of course :)
Index: iostat.8
===================================================================
RCS file: /home/ncvs/src/usr.sbin/iostat/iostat.8,v
retrieving revision 1.24
diff -u -r1.24 iostat.8
--- iostat.8 27 Dec 2002 12:15:37 -0000 1.24
+++ iostat.8 18 Jun 2004 18:56:41 -0000
@@ -70,7 +70,7 @@
statistics
.Sh SYNOPSIS
.Nm
-.Op Fl CdhKIoT?\&
+.Op Fl CdhKIoTxz?\&
.Op Fl c Ar count
.Op Fl M Ar core
.Op Fl n Ar devs
@@ -239,6 +239,12 @@
If no repeat
.Ar count
is specified, the default is infinity.
+.It Fl x
+Print extended device statistics, with one device per line.
+.It Fl z
+If
+.Fl x
+is specified, omit lines for devices with no activity.
.It Fl ?\&
Display a usage statement and exit.
.El
Index: iostat.c
===================================================================
RCS file: /home/ncvs/src/usr.sbin/iostat/iostat.c,v
retrieving revision 1.28
diff -u -r1.28 iostat.c
--- iostat.c 15 Mar 2003 21:59:06 -0000 1.28
+++ iostat.c 19 Jun 2004 06:15:11 -0000
@@ -136,7 +136,7 @@
struct device_selection *dev_select;
int maxshowdevs;
volatile sig_atomic_t headercount;
-int dflag = 0, Iflag = 0, Cflag = 0, Tflag = 0, oflag = 0, Kflag = 0;
+int dflag = 0, Iflag = 0, Cflag = 0, Tflag = 0, oflag = 0, Kflag = 0, xflag = 0, zflag = 0;
/* local function declarations */
static void usage(void);
@@ -156,7 +156,7 @@
* This isn't mentioned in the man page, or the usage statement,
* but it is supported.
*/
- fprintf(stderr, "usage: iostat [-CdhIKoT?] [-c count] [-M core]"
+ fprintf(stderr, "usage: iostat [-CdhIKoTxz?] [-c count] [-M core]"
" [-n devs] [-N system]\n"
"\t [-t type,if,pass] [-w wait] [drives]\n");
}
@@ -184,7 +184,7 @@
matches = NULL;
maxshowdevs = 3;
- while ((c = getopt(argc, argv, "c:CdhIKM:n:N:ot:Tw:?")) != -1) {
+ while ((c = getopt(argc, argv, "c:CdhIKM:n:N:ot:Tw:xz?")) != -1) {
switch(c) {
case 'c':
cflag++;
@@ -238,6 +238,12 @@
if (waittime < 1)
errx(1, "wait time is < 1");
break;
+ case 'x':
+ xflag++;
+ break;
+ case 'z':
+ zflag++;
+ break;
default:
usage();
exit(1);
@@ -270,7 +276,7 @@
* Make sure Tflag and/or Cflag are set if dflag == 0. If dflag is
* greater than 0, they may be 0 or non-zero.
*/
- if (dflag == 0) {
+ if (dflag == 0 && xflag == 0) {
Cflag = 1;
Tflag = 1;
}
@@ -547,18 +553,20 @@
last.cp_time[i] = tmp;
}
- if (Tflag > 0)
+ if (xflag == 0 && Tflag > 0)
printf("%4.0Lf%5.0Lf", cur.tk_nin / etime,
cur.tk_nout/etime);
devstats(hflag, etime, havelast);
- if (Cflag > 0)
- cpustats();
+ if (xflag == 0) {
+ if (Cflag > 0)
+ cpustats();
- printf("\n");
+ printf("\n");
+ }
fflush(stdout);
-
+
if (count >= 0 && --count <= 0)
break;
@@ -584,6 +592,13 @@
{
register int i;
int printed;
+
+ /*
+ * If xflag is set, we need a per-loop header, not a page header, so
+ * just return. We'll print the header in devstats().
+ */
+ if (xflag > 0)
+ return;
if (Tflag > 0)
(void)printf(" tty");
@@ -639,11 +654,29 @@
devstats(int perf_select, long double etime, int havelast)
{
register int dn;
- long double transfers_per_second;
- long double kb_per_transfer, mb_per_second;
+ long double transfers_per_second, transfers_per_second_read, transfers_per_second_write;
+ long double kb_per_transfer, mb_per_second, mb_per_second_read, mb_per_second_write;
u_int64_t total_bytes, total_transfers, total_blocks;
+ long double busy_pct;
+ u_int64_t queue_len;
long double total_mb;
long double blocks_per_second, ms_per_transaction;
+ int firstline = 1;
+
+ if (xflag > 0) {
+ printf (" extended device statistics ");
+ if (Tflag > 0)
+ printf (" tty ");
+ if (Cflag > 0)
+ printf (" cpu ");
+ printf ("\n");
+ printf ("device r/s w/s kr/s kw/s wait actv svc_t %%w %%b ");
+ if (Tflag > 0)
+ printf ("tin tout ");
+ if (Cflag > 0)
+ printf ("us ni sy in id ");
+ printf ("\n");
+ }
for (dn = 0; dn < num_devices; dn++) {
int di;
@@ -661,9 +694,15 @@
DSM_TOTAL_BLOCKS, &total_blocks,
DSM_KB_PER_TRANSFER, &kb_per_transfer,
DSM_TRANSFERS_PER_SECOND, &transfers_per_second,
+ DSM_TRANSFERS_PER_SECOND_READ, &transfers_per_second_read,
+ DSM_TRANSFERS_PER_SECOND_WRITE, &transfers_per_second_write,
DSM_MB_PER_SECOND, &mb_per_second,
+ DSM_MB_PER_SECOND_READ, &mb_per_second_read,
+ DSM_MB_PER_SECOND_WRITE, &mb_per_second_write,
DSM_BLOCKS_PER_SECOND, &blocks_per_second,
DSM_MS_PER_TRANSACTION, &ms_per_transaction,
+ DSM_BUSY_PCT, &busy_pct,
+ DSM_QUEUE_LENGTH, &queue_len,
DSM_NONE) != 0)
errx(1, "%s", devstat_errbuf);
@@ -674,13 +713,44 @@
continue;
}
- if (Kflag) {
+ if (Kflag > 0 || xflag > 0) {
int block_size = cur.dinfo->devices[di].block_size;
total_blocks = total_blocks * (block_size ?
block_size : 512) / 1024;
}
- if (oflag > 0) {
+ if (xflag > 0) {
+ char *devname;
+ asprintf(&devname,"%s%d",
+ cur.dinfo->devices[di].device_name,
+ cur.dinfo->devices[di].unit_number);
+
+ /*
+ * If zflag is set, skip any devices with zero I/O
+ */
+ if (zflag == 0 || transfers_per_second_read > 0.05 ||
+ transfers_per_second_write > 0.05 ||
+ mb_per_second_read > ((long double).0005)/1024 ||
+ mb_per_second_write > ((long double).0005)/1024 || busy_pct > 0.5) {
+ printf ("%-8.8s %5.1Lf %5.1Lf %7.1Lf %7.1Lf %4qu %4qu %5.1Lf %3.0Lf %3.0Lf ",
+ devname,
+ transfers_per_second_read, transfers_per_second_write,
+ mb_per_second_read*1024, mb_per_second_write*1024,
+ (u_int64_t)0, queue_len, ms_per_transaction, (long double)0.0, busy_pct
+ );
+ if (firstline) {
+ /* If this is the first device we're printing, also print
+ CPU or TTY stats if requested */
+ firstline = 0;
+ if (Tflag > 0)
+ printf("%4.0Lf%5.0Lf ", cur.tk_nin / etime,
+ cur.tk_nout/etime);
+ if (Cflag > 0)
+ cpustats();
+ }
+ printf ("\n");
+ }
+ } else if (oflag > 0) {
int msdig = (ms_per_transaction < 100.0) ? 1 : 0;
if (Iflag == 0)
@@ -712,6 +782,18 @@
}
}
}
+
+ if (xflag > 0 && zflag > 0 && firstline == 1 && (Tflag > 0 || Cflag > 0)) {
+ /* If zflag is set and we didn't print any device lines I/O because
+ they were all zero, print TTY/CPU stats */
+ printf("%61s","");
+ if (Tflag > 0)
+ printf("%4.0Lf%5.0Lf ", cur.tk_nin / etime,
+ cur.tk_nout/etime);
+ if (Cflag > 0)
+ cpustats();
+ printf ("\n");
+ }
}
static void
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-bugs
mailing list