1*d8ab6e12SDon Brady /* 2*d8ab6e12SDon Brady * CDDL HEADER START 3*d8ab6e12SDon Brady * 4*d8ab6e12SDon Brady * The contents of this file are subject to the terms of the 5*d8ab6e12SDon Brady * Common Development and Distribution License (the "License"). 6*d8ab6e12SDon Brady * You may not use this file except in compliance with the License. 7*d8ab6e12SDon Brady * 8*d8ab6e12SDon Brady * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9*d8ab6e12SDon Brady * or http://www.opensolaris.org/os/licensing. 10*d8ab6e12SDon Brady * See the License for the specific language governing permissions 11*d8ab6e12SDon Brady * and limitations under the License. 12*d8ab6e12SDon Brady * 13*d8ab6e12SDon Brady * When distributing Covered Code, include this CDDL HEADER in each 14*d8ab6e12SDon Brady * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15*d8ab6e12SDon Brady * If applicable, add the following below this CDDL HEADER, with the 16*d8ab6e12SDon Brady * fields enclosed by brackets "[]" replaced with your own identifying 17*d8ab6e12SDon Brady * information: Portions Copyright [yyyy] [name of copyright owner] 18*d8ab6e12SDon Brady * 19*d8ab6e12SDon Brady * CDDL HEADER END 20*d8ab6e12SDon Brady */ 21*d8ab6e12SDon Brady 22*d8ab6e12SDon Brady /* 23*d8ab6e12SDon Brady * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 24*d8ab6e12SDon Brady */ 25*d8ab6e12SDon Brady 26*d8ab6e12SDon Brady #include <ctype.h> 27*d8ab6e12SDon Brady #include <math.h> 28*d8ab6e12SDon Brady #include <stdio.h> 29*d8ab6e12SDon Brady #include <libzutil.h> 30*d8ab6e12SDon Brady 31*d8ab6e12SDon Brady /* 32*d8ab6e12SDon Brady * Return B_TRUE if "str" is a number string, B_FALSE otherwise. 33*d8ab6e12SDon Brady * Works for integer and floating point numbers. 34*d8ab6e12SDon Brady */ 35*d8ab6e12SDon Brady boolean_t 36*d8ab6e12SDon Brady zfs_isnumber(const char *str) 37*d8ab6e12SDon Brady { 38*d8ab6e12SDon Brady for (; *str; str++) 39*d8ab6e12SDon Brady if (!(isdigit(*str) || (*str == '.'))) 40*d8ab6e12SDon Brady return (B_FALSE); 41*d8ab6e12SDon Brady 42*d8ab6e12SDon Brady return (B_TRUE); 43*d8ab6e12SDon Brady } 44*d8ab6e12SDon Brady 45*d8ab6e12SDon Brady /* 46*d8ab6e12SDon Brady * Convert a number to an appropriately human-readable output. 47*d8ab6e12SDon Brady */ 48*d8ab6e12SDon Brady void 49*d8ab6e12SDon Brady zfs_nicenum_format(uint64_t num, char *buf, size_t buflen, 50*d8ab6e12SDon Brady enum zfs_nicenum_format format) 51*d8ab6e12SDon Brady { 52*d8ab6e12SDon Brady uint64_t n = num; 53*d8ab6e12SDon Brady int index = 0; 54*d8ab6e12SDon Brady const char *u; 55*d8ab6e12SDon Brady const char *units[3][7] = { 56*d8ab6e12SDon Brady [ZFS_NICENUM_1024] = {"", "K", "M", "G", "T", "P", "E"}, 57*d8ab6e12SDon Brady [ZFS_NICENUM_BYTES] = {"B", "K", "M", "G", "T", "P", "E"}, 58*d8ab6e12SDon Brady [ZFS_NICENUM_TIME] = {"ns", "us", "ms", "s", "?", "?", "?"} 59*d8ab6e12SDon Brady }; 60*d8ab6e12SDon Brady 61*d8ab6e12SDon Brady const int units_len[] = {[ZFS_NICENUM_1024] = 6, 62*d8ab6e12SDon Brady [ZFS_NICENUM_BYTES] = 6, 63*d8ab6e12SDon Brady [ZFS_NICENUM_TIME] = 4}; 64*d8ab6e12SDon Brady 65*d8ab6e12SDon Brady const int k_unit[] = { [ZFS_NICENUM_1024] = 1024, 66*d8ab6e12SDon Brady [ZFS_NICENUM_BYTES] = 1024, 67*d8ab6e12SDon Brady [ZFS_NICENUM_TIME] = 1000}; 68*d8ab6e12SDon Brady 69*d8ab6e12SDon Brady double val; 70*d8ab6e12SDon Brady 71*d8ab6e12SDon Brady if (format == ZFS_NICENUM_RAW) { 72*d8ab6e12SDon Brady (void) snprintf(buf, buflen, "%llu", (u_longlong_t)num); 73*d8ab6e12SDon Brady return; 74*d8ab6e12SDon Brady } else if (format == ZFS_NICENUM_RAWTIME && num > 0) { 75*d8ab6e12SDon Brady (void) snprintf(buf, buflen, "%llu", (u_longlong_t)num); 76*d8ab6e12SDon Brady return; 77*d8ab6e12SDon Brady } else if (format == ZFS_NICENUM_RAWTIME && num == 0) { 78*d8ab6e12SDon Brady (void) snprintf(buf, buflen, "%s", "-"); 79*d8ab6e12SDon Brady return; 80*d8ab6e12SDon Brady } 81*d8ab6e12SDon Brady 82*d8ab6e12SDon Brady while (n >= k_unit[format] && index < units_len[format]) { 83*d8ab6e12SDon Brady n /= k_unit[format]; 84*d8ab6e12SDon Brady index++; 85*d8ab6e12SDon Brady } 86*d8ab6e12SDon Brady 87*d8ab6e12SDon Brady u = units[format][index]; 88*d8ab6e12SDon Brady 89*d8ab6e12SDon Brady /* Don't print zero latencies since they're invalid */ 90*d8ab6e12SDon Brady if ((format == ZFS_NICENUM_TIME) && (num == 0)) { 91*d8ab6e12SDon Brady (void) snprintf(buf, buflen, "-"); 92*d8ab6e12SDon Brady } else if ((index == 0) || ((num % 93*d8ab6e12SDon Brady (uint64_t)powl(k_unit[format], index)) == 0)) { 94*d8ab6e12SDon Brady /* 95*d8ab6e12SDon Brady * If this is an even multiple of the base, always display 96*d8ab6e12SDon Brady * without any decimal precision. 97*d8ab6e12SDon Brady */ 98*d8ab6e12SDon Brady (void) snprintf(buf, buflen, "%llu%s", (u_longlong_t)n, u); 99*d8ab6e12SDon Brady 100*d8ab6e12SDon Brady } else { 101*d8ab6e12SDon Brady /* 102*d8ab6e12SDon Brady * We want to choose a precision that reflects the best choice 103*d8ab6e12SDon Brady * for fitting in 5 characters. This can get rather tricky when 104*d8ab6e12SDon Brady * we have numbers that are very close to an order of magnitude. 105*d8ab6e12SDon Brady * For example, when displaying 10239 (which is really 9.999K), 106*d8ab6e12SDon Brady * we want only a single place of precision for 10.0K. We could 107*d8ab6e12SDon Brady * develop some complex heuristics for this, but it's much 108*d8ab6e12SDon Brady * easier just to try each combination in turn. 109*d8ab6e12SDon Brady */ 110*d8ab6e12SDon Brady int i; 111*d8ab6e12SDon Brady for (i = 2; i >= 0; i--) { 112*d8ab6e12SDon Brady val = (double)num / 113*d8ab6e12SDon Brady (uint64_t)powl(k_unit[format], index); 114*d8ab6e12SDon Brady 115*d8ab6e12SDon Brady /* 116*d8ab6e12SDon Brady * Don't print floating point values for time. Note, 117*d8ab6e12SDon Brady * we use floor() instead of round() here, since 118*d8ab6e12SDon Brady * round can result in undesirable results. For 119*d8ab6e12SDon Brady * example, if "num" is in the range of 120*d8ab6e12SDon Brady * 999500-999999, it will print out "1000us". This 121*d8ab6e12SDon Brady * doesn't happen if we use floor(). 122*d8ab6e12SDon Brady */ 123*d8ab6e12SDon Brady if (format == ZFS_NICENUM_TIME) { 124*d8ab6e12SDon Brady if (snprintf(buf, buflen, "%d%s", 125*d8ab6e12SDon Brady (unsigned int) floor(val), u) <= 5) 126*d8ab6e12SDon Brady break; 127*d8ab6e12SDon Brady 128*d8ab6e12SDon Brady } else { 129*d8ab6e12SDon Brady if (snprintf(buf, buflen, "%.*f%s", i, 130*d8ab6e12SDon Brady val, u) <= 5) 131*d8ab6e12SDon Brady break; 132*d8ab6e12SDon Brady } 133*d8ab6e12SDon Brady } 134*d8ab6e12SDon Brady } 135*d8ab6e12SDon Brady } 136*d8ab6e12SDon Brady 137*d8ab6e12SDon Brady /* 138*d8ab6e12SDon Brady * Convert a number to an appropriately human-readable output. 139*d8ab6e12SDon Brady */ 140*d8ab6e12SDon Brady void 141*d8ab6e12SDon Brady zfs_nicenum(uint64_t num, char *buf, size_t buflen) 142*d8ab6e12SDon Brady { 143*d8ab6e12SDon Brady zfs_nicenum_format(num, buf, buflen, ZFS_NICENUM_1024); 144*d8ab6e12SDon Brady } 145*d8ab6e12SDon Brady 146*d8ab6e12SDon Brady /* 147*d8ab6e12SDon Brady * Convert a time to an appropriately human-readable output. 148*d8ab6e12SDon Brady * @num: Time in nanoseconds 149*d8ab6e12SDon Brady */ 150*d8ab6e12SDon Brady void 151*d8ab6e12SDon Brady zfs_nicetime(uint64_t num, char *buf, size_t buflen) 152*d8ab6e12SDon Brady { 153*d8ab6e12SDon Brady zfs_nicenum_format(num, buf, buflen, ZFS_NICENUM_TIME); 154*d8ab6e12SDon Brady } 155*d8ab6e12SDon Brady 156*d8ab6e12SDon Brady /* 157*d8ab6e12SDon Brady * Print out a raw number with correct column spacing 158*d8ab6e12SDon Brady */ 159*d8ab6e12SDon Brady void 160*d8ab6e12SDon Brady zfs_niceraw(uint64_t num, char *buf, size_t buflen) 161*d8ab6e12SDon Brady { 162*d8ab6e12SDon Brady zfs_nicenum_format(num, buf, buflen, ZFS_NICENUM_RAW); 163*d8ab6e12SDon Brady } 164*d8ab6e12SDon Brady 165*d8ab6e12SDon Brady /* 166*d8ab6e12SDon Brady * Convert a number of bytes to an appropriately human-readable output. 167*d8ab6e12SDon Brady */ 168*d8ab6e12SDon Brady void 169*d8ab6e12SDon Brady zfs_nicebytes(uint64_t num, char *buf, size_t buflen) 170*d8ab6e12SDon Brady { 171*d8ab6e12SDon Brady zfs_nicenum_format(num, buf, buflen, ZFS_NICENUM_BYTES); 172*d8ab6e12SDon Brady } 173