diff options
Diffstat (limited to 'cmd/zpool/zpool_main.c')
-rw-r--r-- | cmd/zpool/zpool_main.c | 276 |
1 files changed, 187 insertions, 89 deletions
diff --git a/cmd/zpool/zpool_main.c b/cmd/zpool/zpool_main.c index 0603efdba..072404264 100644 --- a/cmd/zpool/zpool_main.c +++ b/cmd/zpool/zpool_main.c @@ -153,6 +153,7 @@ enum iostat_type { IOS_LATENCY = 1, IOS_QUEUES = 2, IOS_L_HISTO = 3, + IOS_RQ_HISTO = 4, IOS_COUNT, /* always last element */ }; @@ -161,6 +162,62 @@ enum iostat_type { #define IOS_LATENCY_M (1ULL << IOS_LATENCY) #define IOS_QUEUES_M (1ULL << IOS_QUEUES) #define IOS_L_HISTO_M (1ULL << IOS_L_HISTO) +#define IOS_RQ_HISTO_M (1ULL << IOS_RQ_HISTO) + +/* Mask of all the histo bits */ +#define IOS_ANYHISTO_M (IOS_L_HISTO_M | IOS_RQ_HISTO_M) + +/* + * Lookup table for iostat flags to nvlist names. Basically a list + * of all the nvlists a flag requires. Also specifies the order in + * which data gets printed in zpool iostat. + */ +static const char *vsx_type_to_nvlist[IOS_COUNT][11] = { + [IOS_L_HISTO] = { + ZPOOL_CONFIG_VDEV_TOT_R_LAT_HISTO, + ZPOOL_CONFIG_VDEV_TOT_W_LAT_HISTO, + ZPOOL_CONFIG_VDEV_DISK_R_LAT_HISTO, + ZPOOL_CONFIG_VDEV_DISK_W_LAT_HISTO, + ZPOOL_CONFIG_VDEV_SYNC_R_LAT_HISTO, + ZPOOL_CONFIG_VDEV_SYNC_W_LAT_HISTO, + ZPOOL_CONFIG_VDEV_ASYNC_R_LAT_HISTO, + ZPOOL_CONFIG_VDEV_ASYNC_W_LAT_HISTO, + ZPOOL_CONFIG_VDEV_SCRUB_LAT_HISTO, + NULL}, + [IOS_LATENCY] = { + ZPOOL_CONFIG_VDEV_TOT_R_LAT_HISTO, + ZPOOL_CONFIG_VDEV_TOT_W_LAT_HISTO, + ZPOOL_CONFIG_VDEV_DISK_R_LAT_HISTO, + ZPOOL_CONFIG_VDEV_DISK_W_LAT_HISTO, + NULL}, + [IOS_QUEUES] = { + ZPOOL_CONFIG_VDEV_SYNC_R_ACTIVE_QUEUE, + ZPOOL_CONFIG_VDEV_SYNC_W_ACTIVE_QUEUE, + ZPOOL_CONFIG_VDEV_ASYNC_R_ACTIVE_QUEUE, + ZPOOL_CONFIG_VDEV_ASYNC_W_ACTIVE_QUEUE, + ZPOOL_CONFIG_VDEV_SCRUB_ACTIVE_QUEUE, + NULL}, + [IOS_RQ_HISTO] = { + ZPOOL_CONFIG_VDEV_SYNC_IND_R_HISTO, + ZPOOL_CONFIG_VDEV_SYNC_AGG_R_HISTO, + ZPOOL_CONFIG_VDEV_SYNC_IND_W_HISTO, + ZPOOL_CONFIG_VDEV_SYNC_AGG_W_HISTO, + ZPOOL_CONFIG_VDEV_ASYNC_IND_R_HISTO, + ZPOOL_CONFIG_VDEV_ASYNC_AGG_R_HISTO, + ZPOOL_CONFIG_VDEV_ASYNC_IND_W_HISTO, + ZPOOL_CONFIG_VDEV_ASYNC_AGG_W_HISTO, + ZPOOL_CONFIG_VDEV_IND_SCRUB_HISTO, + ZPOOL_CONFIG_VDEV_AGG_SCRUB_HISTO, + NULL}, +}; + + +/* + * Given a cb->cb_flags with a histogram bit set, return the iostat_type. + * Right now, only one histo bit is ever set at one time, so we can + * just do a highbit64(a) + */ +#define IOS_HISTO_IDX(a) (highbit64(a & IOS_ANYHISTO_M) - 1) typedef struct zpool_command { const char *name; @@ -255,7 +312,8 @@ get_usage(zpool_help_t idx) { "[-R root] [-F [-n]]\n" "\t <pool | id> [newpool]\n")); case HELP_IOSTAT: - return (gettext("\tiostat [-T d | u] [-ghHLpPvy] [[-lq]|-w]\n" + return (gettext("\tiostat [-T d | u] [-ghHLpPvy] " + "[[-lq]|[-r|-w]]\n" "\t [[pool ...]|[pool vdev ...]|[vdev ...]] " "[interval [count]]\n")); case HELP_LABELCLEAR: @@ -2531,6 +2589,9 @@ static const name_and_columns_t iostat_top_labels[][IOSTAT_MAX_LABELS] = {NULL}}, [IOS_L_HISTO] = {{"total_wait", 2}, {"disk_wait", 2}, {"sync_queue", 2}, {"async_queue", 2}, {NULL}}, + [IOS_RQ_HISTO] = {{"sync_read", 2}, {"sync_write", 2}, + {"async_read", 2}, {"async_write", 2}, {"scrub", 2}, {NULL}}, + }; /* Shorthand - if "columns" field not set, default to 1 column */ @@ -2544,6 +2605,13 @@ static const name_and_columns_t iostat_bottom_labels[][IOSTAT_MAX_LABELS] = {"activ"}, {"pend"}, {"activ"}, {"pend"}, {"activ"}, {NULL}}, [IOS_L_HISTO] = {{"read"}, {"write"}, {"read"}, {"write"}, {"read"}, {"write"}, {"read"}, {"write"}, {"scrub"}, {NULL}}, + [IOS_RQ_HISTO] = {{"ind"}, {"agg"}, {"ind"}, {"agg"}, {"ind"}, {"agg"}, + {"ind"}, {"agg"}, {"ind"}, {"agg"}, {NULL}}, +}; + +static const char *histo_to_title[] = { + [IOS_L_HISTO] = "latency", + [IOS_RQ_HISTO] = "req_size", }; /* @@ -2563,6 +2631,25 @@ label_array_len(const name_and_columns_t *labels) } /* + * Return the number of strings in a null-terminated string array. + * For example: + * + * const char foo[] = {"bar", "baz", NULL} + * + * returns 2 + */ +static uint64_t +str_array_len(const char *array[]) +{ + uint64_t i = 0; + while (array[i]) + i++; + + return (i); +} + + +/* * Return a default column width for default/latency/queue columns. This does * not include histograms, which have their columns autosized. */ @@ -2673,14 +2760,22 @@ print_iostat_dashes(iostat_cbdata_t *cb, unsigned int force_column_width, uint64_t f; int idx; const name_and_columns_t *labels; + const char *title; + + + if (cb->cb_flags & IOS_ANYHISTO_M) { + title = histo_to_title[IOS_HISTO_IDX(cb->cb_flags)]; + } else if (cb->cb_vdev_names_count) { + title = "vdev"; + } else { + title = "pool"; + } + + namewidth = MAX(MAX(strlen(title), cb->cb_namewidth), + name ? strlen(name) : 0); - if (cb->cb_flags & IOS_L_HISTO_M) - namewidth = MAX(cb->cb_namewidth, strlen("latency")); - else - namewidth = cb->cb_namewidth; if (name) { - namewidth = MAX(cb->cb_namewidth, strlen(name)); printf("%-*s", namewidth, name); } else { for (i = 0; i < namewidth; i++) @@ -2727,22 +2822,28 @@ print_iostat_header_impl(iostat_cbdata_t *cb, unsigned int force_column_width, const char *histo_vdev_name) { unsigned int namewidth; - uint64_t flags = cb->cb_flags; + const char *title; - if (flags & IOS_L_HISTO_M) - namewidth = MAX(cb->cb_namewidth, strlen("latency")); - else - namewidth = cb->cb_namewidth; + if (cb->cb_flags & IOS_ANYHISTO_M) { + title = histo_to_title[IOS_HISTO_IDX(cb->cb_flags)]; + } else if (cb->cb_vdev_names_count) { + title = "vdev"; + } else { + title = "pool"; + } - if (flags & IOS_L_HISTO_M) + namewidth = MAX(MAX(strlen(title), cb->cb_namewidth), + histo_vdev_name ? strlen(histo_vdev_name) : 0); + + if (histo_vdev_name) printf("%-*s", namewidth, histo_vdev_name); else printf("%*s", namewidth, ""); + print_iostat_labels(cb, force_column_width, iostat_top_labels); - printf("%-*s", namewidth, flags & IOS_L_HISTO_M ? "latency" : - cb->cb_vdev_names_count ? "vdev" : "pool"); + printf("%-*s", namewidth, title); print_iostat_labels(cb, force_column_width, iostat_bottom_labels); @@ -2918,6 +3019,7 @@ print_iostat_histo(struct stat_array *nva, unsigned int len, uint64_t val; enum zfs_nicenum_format format; unsigned int buckets; + unsigned int start_bucket; if (cb->cb_literal) format = ZFS_NICENUM_RAW; @@ -2927,12 +3029,25 @@ print_iostat_histo(struct stat_array *nva, unsigned int len, /* All these histos are the same size, so just use nva[0].count */ buckets = nva[0].count; - for (j = 0; j < buckets; j++) { - /* Ending range of this bucket */ - val = (1UL << (j + 1)) - 1; + if (cb->cb_flags & IOS_RQ_HISTO_M) { + /* Start at 512 - req size should never be lower than this */ + start_bucket = 9; + } else { + start_bucket = 0; + } + for (j = start_bucket; j < buckets; j++) { /* Print histogram bucket label */ - zfs_nicetime(val, buf, sizeof (buf)); + if (cb->cb_flags & IOS_L_HISTO_M) { + /* Ending range of this bucket */ + val = (1UL << (j + 1)) - 1; + zfs_nicetime(val, buf, sizeof (buf)); + } else { + /* Request size (starting range of bucket) */ + val = (1UL << j); + zfs_nicenum(val, buf, sizeof (buf)); + } + if (cb->cb_scripted) printf("%llu", (u_longlong_t) val); else @@ -2962,30 +3077,29 @@ print_iostat_histos(iostat_cbdata_t *cb, nvlist_t *oldnv, unsigned int column_width; unsigned int namewidth; unsigned int entire_width; - - const char *names[] = { - ZPOOL_CONFIG_VDEV_TOT_R_LAT_HISTO, - ZPOOL_CONFIG_VDEV_TOT_W_LAT_HISTO, - ZPOOL_CONFIG_VDEV_DISK_R_LAT_HISTO, - ZPOOL_CONFIG_VDEV_DISK_W_LAT_HISTO, - ZPOOL_CONFIG_VDEV_SYNC_R_LAT_HISTO, - ZPOOL_CONFIG_VDEV_SYNC_W_LAT_HISTO, - ZPOOL_CONFIG_VDEV_ASYNC_R_LAT_HISTO, - ZPOOL_CONFIG_VDEV_ASYNC_W_LAT_HISTO, - ZPOOL_CONFIG_VDEV_SCRUB_LAT_HISTO, - }; + enum iostat_type type; struct stat_array *nva; - nva = calc_and_alloc_stats_ex(names, ARRAY_SIZE(names), oldnv, newnv); + const char **names; + unsigned int names_len; + + /* What type of histo are we? */ + type = IOS_HISTO_IDX(cb->cb_flags); + + /* Get NULL-terminated array of nvlist names for our histo */ + names = vsx_type_to_nvlist[type]; + names_len = str_array_len(names); /* num of names */ + + nva = calc_and_alloc_stats_ex(names, names_len, oldnv, newnv); if (cb->cb_literal) { column_width = MAX(5, - (unsigned int) log10(stat_histo_max(nva, - ARRAY_SIZE(names))) + 1); + (unsigned int) log10(stat_histo_max(nva, names_len)) + 1); } else { column_width = 5; } - namewidth = MAX(cb->cb_namewidth, strlen("latency")); + namewidth = MAX(cb->cb_namewidth, + strlen(histo_to_title[IOS_HISTO_IDX(cb->cb_flags)])); /* * Calculate the entire line width of what we're printing. The @@ -2998,17 +3112,17 @@ print_iostat_histos(iostat_cbdata_t *cb, nvlist_t *oldnv, /* |__________| <--- entire_width */ /* */ entire_width = namewidth + (column_width + 2) * - label_array_len(iostat_bottom_labels[IOS_L_HISTO]); + label_array_len(iostat_bottom_labels[type]); if (cb->cb_scripted) printf("%s\n", name); else print_iostat_header_impl(cb, column_width, name); - print_iostat_histo(nva, ARRAY_SIZE(names), cb, column_width, + print_iostat_histo(nva, names_len, cb, column_width, namewidth, scale); - free_calc_stats(nva, ARRAY_SIZE(names)); + free_calc_stats(nva, names_len); if (!cb->cb_scripted) print_solid_separator(entire_width); } @@ -3219,7 +3333,7 @@ print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv, * Print the vdev name unless it's is a histogram. Histograms * display the vdev name in the header itself. */ - if (!(cb->cb_flags & IOS_L_HISTO_M)) { + if (!(cb->cb_flags & IOS_ANYHISTO_M)) { if (cb->cb_scripted) { printf("%s", name); } else { @@ -3234,7 +3348,7 @@ print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv, /* Calculate our scaling factor */ tdelta = newvs->vs_timestamp - oldvs->vs_timestamp; - if ((oldvs->vs_timestamp == 0) && (cb->cb_flags & IOS_L_HISTO_M)) { + if ((oldvs->vs_timestamp == 0) && (cb->cb_flags & IOS_ANYHISTO_M)) { /* * If we specify printing histograms with no time interval, then * print the histogram numbers over the entire lifetime of the @@ -3256,12 +3370,12 @@ print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv, print_iostat_latency(cb, oldnv, newnv, scale); if (cb->cb_flags & IOS_QUEUES_M) print_iostat_queues(cb, oldnv, newnv, scale); - if (cb->cb_flags & IOS_L_HISTO_M) { + if (cb->cb_flags & IOS_ANYHISTO_M) { printf("\n"); print_iostat_histos(cb, oldnv, newnv, scale, name); } - if (!(cb->cb_flags & IOS_L_HISTO_M)) + if (!(cb->cb_flags & IOS_ANYHISTO_M)) printf("\n"); free(calcvs); @@ -3303,7 +3417,7 @@ children: */ if (num_logs(newnv) > 0) { - if ((!(cb->cb_flags & IOS_L_HISTO_M)) && !cb->cb_scripted && + if ((!(cb->cb_flags & IOS_ANYHISTO_M)) && !cb->cb_scripted && !cb->cb_vdev_names) { print_iostat_dashes(cb, 0, "logs"); } @@ -3337,7 +3451,7 @@ children: return (ret); if (children > 0) { - if ((!(cb->cb_flags & IOS_L_HISTO_M)) && !cb->cb_scripted && + if ((!(cb->cb_flags & IOS_ANYHISTO_M)) && !cb->cb_scripted && !cb->cb_vdev_names) { print_iostat_dashes(cb, 0, "cache"); } @@ -3399,9 +3513,10 @@ print_iostat(zpool_handle_t *zhp, void *data) ret = print_vdev_stats(zhp, zpool_get_name(zhp), oldnvroot, newnvroot, cb, 0); - if ((ret != 0) && !(cb->cb_flags & IOS_L_HISTO_M) && !cb->cb_scripted && - cb->cb_verbose && !cb->cb_vdev_names_count) - print_iostat_separator(cb); + if ((ret != 0) && !(cb->cb_flags & IOS_ANYHISTO_M) && + !cb->cb_scripted && cb->cb_verbose && !cb->cb_vdev_names_count) { + print_iostat_separator(cb); + } return (ret); } @@ -3553,37 +3668,6 @@ get_stat_flags_cb(zpool_handle_t *zhp, void *data) uint64_t flags = 0; int i, j; - /* - * Lookup table for extended iostat flags to nvlist names. - * Basically a list of all the nvpairs a flag requires. - */ - static const char *vsx_type_to_nvlist[IOS_COUNT][10] = { - [IOS_L_HISTO] = { - ZPOOL_CONFIG_VDEV_TOT_R_LAT_HISTO, - ZPOOL_CONFIG_VDEV_TOT_W_LAT_HISTO, - ZPOOL_CONFIG_VDEV_DISK_R_LAT_HISTO, - ZPOOL_CONFIG_VDEV_DISK_W_LAT_HISTO, - ZPOOL_CONFIG_VDEV_SYNC_R_LAT_HISTO, - ZPOOL_CONFIG_VDEV_SYNC_W_LAT_HISTO, - ZPOOL_CONFIG_VDEV_ASYNC_R_LAT_HISTO, - ZPOOL_CONFIG_VDEV_ASYNC_W_LAT_HISTO, - ZPOOL_CONFIG_VDEV_SCRUB_LAT_HISTO, - NULL}, - [IOS_LATENCY] = { - ZPOOL_CONFIG_VDEV_TOT_R_LAT_HISTO, - ZPOOL_CONFIG_VDEV_TOT_W_LAT_HISTO, - ZPOOL_CONFIG_VDEV_DISK_R_LAT_HISTO, - ZPOOL_CONFIG_VDEV_DISK_W_LAT_HISTO, - NULL}, - [IOS_QUEUES] = { - ZPOOL_CONFIG_VDEV_SYNC_R_ACTIVE_QUEUE, - ZPOOL_CONFIG_VDEV_SYNC_W_ACTIVE_QUEUE, - ZPOOL_CONFIG_VDEV_ASYNC_R_ACTIVE_QUEUE, - ZPOOL_CONFIG_VDEV_ASYNC_W_ACTIVE_QUEUE, - ZPOOL_CONFIG_VDEV_SCRUB_ACTIVE_QUEUE, - NULL} - }; - config = zpool_get_config(zhp, NULL); verify(nvlist_lookup_nvlist(config, ZPOOL_CONFIG_VDEV_TREE, &nvroot) == 0); @@ -3818,7 +3902,7 @@ fsleep(float sec) { /* - * zpool iostat [-ghHLpPvy] [[-lq]-w] [-n name] [-T d|u] + * zpool iostat [-ghHLpPvy] [[-lq]|[-r|-w]] [-n name] [-T d|u] * [[ pool ...]|[pool vdev ...]|[vdev ...]] * [interval [count]] * @@ -3832,7 +3916,8 @@ fsleep(float sec) { * by a single tab. * -l Display average latency * -q Display queue depths - * -w Display histograms + * -w Display latency histograms + * -r Display request size histogram * -T Display a timestamp in date(1) or Unix format * * This command can be tricky because we want to be able to deal with pool @@ -3851,7 +3936,7 @@ zpool_do_iostat(int argc, char **argv) unsigned long count = 0; zpool_list_t *list; boolean_t verbose = B_FALSE; - boolean_t latency = B_FALSE, histo = B_FALSE; + boolean_t latency = B_FALSE, l_histo = B_FALSE, rq_histo = B_FALSE; boolean_t queues = B_FALSE, parsable = B_FALSE, scripted = B_FALSE; boolean_t omit_since_boot = B_FALSE; boolean_t guid = B_FALSE; @@ -3861,12 +3946,12 @@ zpool_do_iostat(int argc, char **argv) /* Used for printing error message */ const char flag_to_arg[] = {[IOS_LATENCY] = 'l', [IOS_QUEUES] = 'q', - [IOS_L_HISTO] = 'w'}; + [IOS_L_HISTO] = 'w', [IOS_RQ_HISTO] = 'r'}; uint64_t unsupported_flags; /* check options */ - while ((c = getopt(argc, argv, "gLPT:vyhplqwH")) != -1) { + while ((c = getopt(argc, argv, "gLPT:vyhplqrwH")) != -1) { switch (c) { case 'g': guid = B_TRUE; @@ -3896,7 +3981,10 @@ zpool_do_iostat(int argc, char **argv) scripted = B_TRUE; break; case 'w': - histo = B_TRUE; + l_histo = B_TRUE; + break; + case 'r': + rq_histo = B_TRUE; break; case 'y': omit_since_boot = B_TRUE; @@ -3997,10 +4085,18 @@ zpool_do_iostat(int argc, char **argv) return (1); } - if (histo && (queues || latency)) { + if ((l_histo || rq_histo) && (queues || latency)) { + pool_list_free(list); + (void) fprintf(stderr, + gettext("[-r|-w] isn't allowed with [-q|-l]\n")); + usage(B_FALSE); + return (1); + } + + if (l_histo && rq_histo) { pool_list_free(list); (void) fprintf(stderr, - gettext("-w isn't allowed with [-q|-l]\n")); + gettext("Only one of [-r|-w] can be passed at a time\n")); usage(B_FALSE); return (1); } @@ -4010,13 +4106,15 @@ zpool_do_iostat(int argc, char **argv) */ cb.cb_list = list; - if (histo) { + if (l_histo) { /* * Histograms tables look out of place when you try to display * them with the other stats, so make a rule that you can only * print histograms by themselves. */ cb.cb_flags = IOS_L_HISTO_M; + } else if (rq_histo) { + cb.cb_flags = IOS_RQ_HISTO_M; } else { cb.cb_flags = IOS_DEFAULT_M; if (latency) @@ -4088,7 +4186,7 @@ zpool_do_iostat(int argc, char **argv) */ if (((++cb.cb_iteration == 1 && !skip) || (skip != verbose)) && - (!(cb.cb_flags & IOS_L_HISTO_M)) && + (!(cb.cb_flags & IOS_ANYHISTO_M)) && !cb.cb_scripted) print_iostat_header(&cb); @@ -4108,8 +4206,8 @@ zpool_do_iostat(int argc, char **argv) * we also want an ending separator. */ if (((npools > 1 && !verbose && - !(cb.cb_flags & IOS_L_HISTO_M)) || - (!(cb.cb_flags & IOS_L_HISTO_M) && + !(cb.cb_flags & IOS_ANYHISTO_M)) || + (!(cb.cb_flags & IOS_ANYHISTO_M) && cb.cb_vdev_names_count)) && !cb.cb_scripted) { print_iostat_separator(&cb); |