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