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