WARNING : long and verbose .. sorry. ALL : While doing various performance tests and measurements of IO rates with a zpool I found that the output from zpool iostat poolname was not really ready for plotting by gnuplot. The output from zpool iostat poolname looks like so : # zpool iostat zpool0 15 capacity operations bandwidth pool used avail read write read write ---------- ----- ----- ----- ----- ----- ----- zpool0 292K 1.63T 48 91 2.96M 6.10M zpool0 292K 1.63T 0 0 0 0 zpool0 10.0M 1.63T 0 373 0 878K zpool0 27.4M 1.63T 0 567 0 1.36M zpool0 43.9M 1.63T 0 612 0 1.44M zpool0 72.1M 1.63T 0 566 0 1.32M zpool0 101M 1.63T 0 1.16K 0 2.80M zpool0 156M 1.63T 0 1.17K 0 2.81M zpool0 183M 1.63T 0 1.13K 0 2.73M zpool0 237M 1.63T 0 1.14K 0 2.74M . . . I note that the headers there are hard coded into zpool_main.c and there appears to be no option to disable them, thus : static void print_iostat_header(iostat_cbdata_t *cb) { (void) printf("%*s capacity operations bandwidth\n", cb->cb_namewidth, ""); (void) printf("%-*s used avail read write read write\n", cb->cb_namewidth, "pool"); print_iostat_separator(cb); } and here we see : static void print_iostat_separator(iostat_cbdata_t *cb) { int i = 0; for (i = 0; i < cb->cb_namewidth; i++) (void) printf("-"); (void) printf(" ----- ----- ----- ----- ----- -----\n"); } However these headers are only ever printed once while the verbose option "-v" is NOT in effect. We do see them repeated over and over when the verbose flag is engaged : # zpool iostat -v zpool0 5 capacity operations bandwidth pool used avail read write read write ----------- ----- ----- ----- ----- ----- ----- zpool0 148K 1.63T 0 21 635 2.64M mirror 14.5K 278G 0 3 112 449K c2t8d0 - - 0 3 52 449K c3t8d0 - - 0 3 95 449K mirror 47K 278G 0 3 77 449K c2t9d0 - - 0 3 52 449K c3t9d0 - - 0 3 63 449K mirror 47.5K 278G 0 3 69 449K c2t10d0 - - 0 3 52 449K c3t10d0 - - 0 3 42 449K mirror 14K 278G 0 3 97 451K c2t11d0 - - 0 3 74 451K c3t11d0 - - 0 3 52 451K mirror 6K 278G 0 3 125 451K c2t12d0 - - 0 3 73 451K c3t12d0 - - 0 3 94 451K mirror 19.5K 278G 0 3 154 451K c2t13d0 - - 0 3 147 451K c3t13d0 - - 0 3 31 451K ----------- ----- ----- ----- ----- ----- ----- It seems perfectly reasonable to have those headers repeated over and over when we expect verbose reports. The issue that I have is with the summary reports where we get the headers only once. I wanted to take iostat data from zpool iostat poolname and be able to directly pass it through awk and into a datafile for processing into nice graphs. I find that gnuplot does this nicely. However the units of the data may vary from Kilobytes ( K ), Megabytes ( M ) and perhaps a simple digit zero with no suffix at all. I can only presume that we may also see Gigabyes ( G ) and perhaps some day even Terabytes ( T ). I was thinking that we could add in an option for the iostat subcommand for raw output as simple integers. Here we could have a "-r" option which would work only when the verbose option is NOT present. At least for now. So then we see this : static const char * get_usage(zpool_help_t idx) { switch (idx) { . . . /* * I may have the option syntax wrong here but the intent is that one may * specify the -r OR the -v but not both at the same time. */ case HELP_IOSTAT: return (gettext("\tiostat {[-r]|[-v]} [pool] ... [interval " "[count]]\n")); . . . } abort(); /* NOTREACHED */ } The iostat_cbdata struct would need a new int element also : typedef struct iostat_cbdata { zpool_list_t *cb_list; /* * The cb_raw int is added here by Dennis Clarke */ int cb_raw; int cb_verbose; int cb_iteration; int cb_namewidth; } iostat_cbdata_t; I don''t think that any change to print_vdev_stats is required because the creation of the suffixes seems to occur with print_one_stat : /* * Display a single statistic. */ void print_one_stat(uint64_t value) { char buf[64]; zfs_nicenum(value, buf, sizeof (buf)); (void) printf(" %5s", buf); } which in tern calls the zfs_nicenum which seems to be included at the top with the #include <libzfs.h> where we see this : in "libzfs_util.c" line 449 of 847 /* * Convert a number to an appropriately human-readable output. */ void zfs_nicenum(uint64_t num, char *buf, size_t buflen) { uint64_t n = num; int index = 0; char u; while (n >= 1024) { n /= 1024; /* this is slick. a comment would help */ index++; } u = " KMGTPE"[index]; /* would be nice to have bytes "b" also */ if (index == 0) { (void) snprintf(buf, buflen, "%llu", n); } else if ((num & ((1ULL << 10 * index) - 1)) == 0) { /* * If this is an even multiple of the base, always display * without any decimal precision. (void) snprintf(buf, buflen, "%llu%c", n, u); } else { /* * We want to choose a precision that reflects the best * choice for fitting in 5 characters. This can get rather * tricky when we have numbers that are very close to an * order of magnitude. * For example, when displaying 10239 (which is really * 9.999K), we want only a single place of precision for * 10.0K. We could * develop some complex heuristics for this, but it''s much * easier just to try each combination in turn. */ int i; for (i = 2; i >= 0; i--) { (void) snprintf(buf, buflen, "%.*f%c", i, (double)num / (1ULL << 10 * index), u); if (strlen(buf) <= 5) break; } } } I think I could really use /* * just print the integer */ void zfs_rawnum(uint64_t num, char *buf, size_t buflen) { ... } or perhaps modify print_one_stat(uint64_t value) such that we look to see if the raw option is set and then print the uint64_t value right then and there without ever calling zfs_nicenum. This means that only zpool_main.c would change and the raw integers would be printed by print_one_stat quite neatly. Any thoughts ? - Dennis Clarke