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

_______________________________________________
zfs-discuss mailing list
zfs-discuss@opensolaris.org
http://mail.opensolaris.org/mailman/listinfo/zfs-discuss

Reply via email to