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