diff options
Diffstat (limited to 'lib/libzfs/libzfs_util.c')
-rw-r--r-- | lib/libzfs/libzfs_util.c | 94 |
1 files changed, 82 insertions, 12 deletions
diff --git a/lib/libzfs/libzfs_util.c b/lib/libzfs/libzfs_util.c index 57c2ac853..926ed4ed8 100644 --- a/lib/libzfs/libzfs_util.c +++ b/lib/libzfs/libzfs_util.c @@ -596,27 +596,49 @@ zfs_strdup(libzfs_handle_t *hdl, const char *str) * Convert a number to an appropriately human-readable output. */ void -zfs_nicenum(uint64_t num, char *buf, size_t buflen) +zfs_nicenum_format(uint64_t num, char *buf, size_t buflen, + enum zfs_nicenum_format format) { uint64_t n = num; int index = 0; - char u; + const char *u; + const char *units[3][7] = { + [ZFS_NICENUM_1024] = {"", "K", "M", "G", "T", "P", "E"}, + [ZFS_NICENUM_TIME] = {"ns", "us", "ms", "s", "?", "?", "?"} + }; + + const int units_len[] = {[ZFS_NICENUM_1024] = 6, + [ZFS_NICENUM_TIME] = 4}; + + const int k_unit[] = { [ZFS_NICENUM_1024] = 1024, + [ZFS_NICENUM_TIME] = 1000}; - while (n >= 1024 && index < 6) { - n /= 1024; + double val; + + if (format == ZFS_NICENUM_RAW) { + snprintf(buf, buflen, "%llu", (u_longlong_t) num); + return; + } + + + while (n >= k_unit[format] && index < units_len[format]) { + n /= k_unit[format]; index++; } - u = " KMGTPE"[index]; + u = units[format][index]; - if (index == 0) { - (void) snprintf(buf, buflen, "%llu", (u_longlong_t) n); - } else if ((num & ((1ULL << 10 * index) - 1)) == 0) { + /* Don't print 0ns times */ + if ((format == ZFS_NICENUM_TIME) && (num == 0)) { + (void) snprintf(buf, buflen, "-"); + } else if ((index == 0) || ((num % + (uint64_t) powl(k_unit[format], index)) == 0)) { /* * If this is an even multiple of the base, always display * without any decimal precision. */ - (void) snprintf(buf, buflen, "%llu%c", (u_longlong_t) n, u); + (void) snprintf(buf, buflen, "%llu%s", (u_longlong_t) n, u); + } else { /* * We want to choose a precision that reflects the best choice @@ -629,13 +651,61 @@ zfs_nicenum(uint64_t num, char *buf, size_t buflen) */ int i; for (i = 2; i >= 0; i--) { - if (snprintf(buf, buflen, "%.*f%c", i, - (double)num / (1ULL << 10 * index), u) <= 5) - break; + val = (double) num / + (uint64_t) powl(k_unit[format], index); + + /* + * Don't print floating point values for time. Note, + * we use floor() instead of round() here, since + * round can result in undesirable results. For + * example, if "num" is in the range of + * 999500-999999, it will print out "1000us". This + * doesn't happen if we use floor(). + */ + if (format == ZFS_NICENUM_TIME) { + if (snprintf(buf, buflen, "%d%s", + (unsigned int) floor(val), u) <= 5) + break; + + } else { + if (snprintf(buf, buflen, "%.*f%s", i, + val, u) <= 5) + break; + } } } } +/* + * Convert a number to an appropriately human-readable output. + */ +void +zfs_nicenum(uint64_t num, char *buf, size_t buflen) +{ + zfs_nicenum_format(num, buf, buflen, ZFS_NICENUM_1024); +} + +/* + * Convert a time to an appropriately human-readable output. + * @num: Time in nanoseconds + */ +void +zfs_nicetime(uint64_t num, char *buf, size_t buflen) +{ + zfs_nicenum_format(num, buf, buflen, ZFS_NICENUM_TIME); +} + +/* + * Print out a raw number with correct column spacing + */ +void +zfs_niceraw(uint64_t num, char *buf, size_t buflen) +{ + zfs_nicenum_format(num, buf, buflen, ZFS_NICENUM_RAW); +} + + + void libzfs_print_on_error(libzfs_handle_t *hdl, boolean_t printerr) { |