[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Patch for iostat, fine-grained read/write statistics.



This patch adds two new types of statistics to iostat:
1. Number of separate read and write transfers.
2. Number of separate read and write bytes.

Here are two examples:

% iostat -x -I
             wd0             cd0             fd0
    rxfr    wxfr    rxfr    wxfr    rxfr    wxfr
   22564    6087       0       0       0       0

This shows the absolute numbers of both read and write
transfers for each device. Why is that interesting, you
might ask. The primary reason is to have more fine-grained
control over write transfers when dealing with solid state
media, e.g. Compact Flash (much used in embedded systems).
These cards are said to handle only a limited amount of
write transfers before potential failure, see
<URL:http://www.sandisk.com/pdf/oem/WPaperWearLevelv1.0.pdf>

Another example shows read and written bytes per second:

% iostat -b
             wd0             cd0             fd0
    rB/s    wB/s    rB/s    wB/s    rB/s    wB/s
    3179    2365       0       0       0       0

(On a sidenote, this was on a seemingly idle system, so I
was a bit surprised by those values. Why are the numbers
so high?)


Here's the patch:

% diff -ru usr.sbin/iostat/iostat.c myusr.sbin/iostat/iostat.c
--- usr.sbin/iostat/iostat.c	Fri Apr  1 05:32:47 2005
+++ myusr.sbin/iostat/iostat.c	Sun Jul 24 18:43:07 2005
@@ -109,11 +109,15 @@
 #define SHOW_TTY	0x0002
 #define SHOW_STATS_1	0x0004
 #define SHOW_STATS_2	0x0008
+#define SHOW_XFERS	0x0010
+#define SHOW_BYTES	0x0020
 #define SHOW_TOTALS	0x0080
 
 static void cpustats(void);
 static void disk_stats(double);
 static void disk_stats2(double);
+static void disk_xfers(double);
+static void disk_bytes(double);
 static void sigheader(int);
 static void header(void);
 static void usage(void);
@@ -130,8 +134,11 @@
 	int ch, hdrcnt;
 	struct timeval	tv;
 
-	while ((ch = getopt(argc, argv, "Cc:dDIM:N:Tw:")) != -1)
+	while ((ch = getopt(argc, argv, "bCc:dDIM:N:Tw:x")) != -1)
 		switch(ch) {
+		case 'b':
+			todo |= SHOW_BYTES;
+			break;
 		case 'c':
 			if ((reps = atoi(optarg)) <= 0)
 				errx(1, "repetition count <= 0.");
@@ -161,6 +168,9 @@
 			if ((interval = atoi(optarg)) <= 0)
 				errx(1, "interval <= 0.");
 			break;
+		case 'x':
+			todo |= SHOW_XFERS;
+			break;
 		case '?':
 		default:
 			usage();
@@ -168,7 +178,7 @@
 	argc -= optind;
 	argv += optind;
 
-	if (!ISSET(todo, SHOW_CPU | SHOW_TTY | SHOW_STATS_1 | SHOW_STATS_2))
+	if (!ISSET(todo, SHOW_CPU | SHOW_TTY | SHOW_STATS_1 | SHOW_STATS_2 | SHOW_XFERS | SHOW_BYTES))
 		todo |= SHOW_CPU | SHOW_TTY | SHOW_STATS_1;
 
 	dkinit(0);
@@ -227,6 +237,16 @@
 		if (cur.dk_select[i])
 			(void)printf(" %13.13s ", cur.dk_name[i]);
 
+	if (ISSET(todo, SHOW_XFERS))
+	for (i = 0; i < dk_ndrive; i++)
+		if (cur.dk_select[i])
+			(void)printf("  %14.14s", cur.dk_name[i]);
+
+	if (ISSET(todo, SHOW_BYTES))
+	for (i = 0; i < dk_ndrive; i++)
+		if (cur.dk_select[i])
+			(void)printf("  %14.14s", cur.dk_name[i]);
+
 	if (ISSET(todo, SHOW_CPU))
 		(void)printf("            cpu");
 	printf("\n");
@@ -248,6 +268,22 @@
 		if (cur.dk_select[i])
 			(void)printf("   KB xfr time ");
 
+	if (ISSET(todo, SHOW_XFERS))
+	for (i = 0; i < dk_ndrive; i++)
+		if (cur.dk_select[i])
+			if (ISSET(todo, SHOW_TOTALS))
+				(void)printf("    rxfr    wxfr");
+			else
+				(void)printf("  rxfr/s  wxfr/s");
+
+	if (ISSET(todo, SHOW_BYTES))
+	for (i = 0; i < dk_ndrive; i++)
+		if (cur.dk_select[i])
+			if (ISSET(todo, SHOW_TOTALS))
+				(void)printf("  rBytes  wBytes");
+			else
+				(void)printf("    rB/s    wB/s");
+
 	if (ISSET(todo, SHOW_CPU))
 		(void)printf(" us ni sy in id");
 	printf("\n");
@@ -316,6 +352,46 @@
 }
 
 static void
+disk_xfers(double etime)
+{
+	int dn;
+	double atime;
+
+	for (dn = 0; dn < dk_ndrive; ++dn) {
+		if (!cur.dk_select[dn])
+			continue;
+
+		/* average read transfers per second. */
+		(void)printf(" %7.0f",
+		    cur.dk_rxfer[dn] / etime);
+
+		/* average write transfers per second. */
+		(void)printf(" %7.0f",
+		    cur.dk_wxfer[dn] / etime);
+	}
+}
+
+static void
+disk_bytes(double etime)
+{
+	int dn;
+	double atime;
+
+	for (dn = 0; dn < dk_ndrive; ++dn) {
+		if (!cur.dk_select[dn])
+			continue;
+
+		/* average read bytes per second. */
+		(void)printf(" %7.0f",
+		    cur.dk_rbytes[dn] / etime);
+
+		/* average write bytes per second. */
+		(void)printf(" %7.0f",
+		    cur.dk_wbytes[dn] / etime);
+	}
+}
+
+static void
 cpustats(void)
 {
 	int state;
@@ -335,7 +411,7 @@
 usage(void)
 {
 	(void)fprintf(stderr,
-"usage: iostat [-CdDIT] [-c count] [-M core] [-N system] [-w wait] [drives]\n");
+"usage: iostat [-bCdDITx] [-c count] [-M core] [-N system] [-w wait] [drives]\n");
 	exit(1);
 }
 
@@ -369,6 +445,12 @@
 
 	if (ISSET(todo, SHOW_STATS_2))
 		disk_stats2(etime);
+
+	if (ISSET(todo, SHOW_XFERS))
+		disk_xfers(etime);
+
+	if (ISSET(todo, SHOW_BYTES))
+		disk_bytes(etime);
 
 	if (ISSET(todo, SHOW_CPU))
 		cpustats();



Visit your host, monkey.org