From owner-freebsd-bugs@FreeBSD.ORG Fri Jul 9 03:00:42 2004 Return-Path: Delivered-To: freebsd-bugs@hub.freebsd.org Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id BF10D16A4D3 for ; Fri, 9 Jul 2004 03:00:41 +0000 (GMT) Received: from freefall.freebsd.org (freefall.freebsd.org [216.136.204.21]) by mx1.FreeBSD.org (Postfix) with ESMTP id BAFAB43D4C for ; Fri, 9 Jul 2004 03:00:41 +0000 (GMT) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (gnats@localhost [127.0.0.1]) by freefall.freebsd.org (8.12.11/8.12.11) with ESMTP id i6930fmP025850 for ; Fri, 9 Jul 2004 03:00:41 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.12.11/8.12.11/Submit) id i6930fNQ025843; Fri, 9 Jul 2004 03:00:41 GMT (envelope-from gnats) Resent-Date: Fri, 9 Jul 2004 03:00:41 GMT Resent-Message-Id: <200407090300.i6930fNQ025843@freefall.freebsd.org> Resent-From: FreeBSD-gnats-submit@FreeBSD.org (GNATS Filer) Resent-To: freebsd-bugs@FreeBSD.org Resent-Reply-To: FreeBSD-gnats-submit@FreeBSD.org, Dan Nelson Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125]) by hub.freebsd.org (Postfix) with ESMTP id CD4A816A4CE for ; Fri, 9 Jul 2004 02:51:33 +0000 (GMT) Received: from dan.emsphone.com (dan.emsphone.com [199.67.51.101]) by mx1.FreeBSD.org (Postfix) with ESMTP id 6483543D1D for ; Fri, 9 Jul 2004 02:51:33 +0000 (GMT) (envelope-from dan@dan.emsphone.com) Received: (from dan@localhost) by dan.emsphone.com (8.12.10/8.12.10) id i692pWO2048706; Thu, 8 Jul 2004 21:51:32 -0500 (CDT) (envelope-from dan) Message-Id: <200407090251.i692pWO2048706@dan.emsphone.com> Date: Thu, 8 Jul 2004 21:51:32 -0500 (CDT) From: Dan Nelson To: FreeBSD-gnats-submit@FreeBSD.org X-Send-Pr-Version: 3.113 Subject: bin/68840: [PATCH] Add Solaris-style -x flag to iostat X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.1 Precedence: list Reply-To: Dan Nelson List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 09 Jul 2004 03:00:43 -0000 >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@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: