]> git.ipfire.org Git - thirdparty/zstd.git/commitdiff
Avoid `snprintf()` in Preparing Human-Readable Sizes; Improve Formatting
authorW. Felix Handte <w@felixhandte.com>
Wed, 9 Jun 2021 17:05:44 +0000 (13:05 -0400)
committerW. Felix Handte <w@felixhandte.com>
Thu, 10 Jun 2021 16:53:07 +0000 (12:53 -0400)
This produces the following formatting:

   Size    | `zstd` | `ls -lh`
---------- | ------ | --------
1          | 1      | 1
12         | 12     | 12
123        | 123    | 123
1234       | 1.21K  | 1.3K
12345      | 12.1K  | 13K
123456     | 121K   | 121K
1234567    | 1.18M  | 1.2M
12345678   | 11.8M  | 12M
123456789  | 118M   | 118M
1234567890 | 1.15G  | 1.2G
999        | 999    | 999
1000       | 1000   | 1000
1001       | 1001   | 1001
1023       | 1023   | 1023
1024       | 1.000K | 1.0K
1025       | 1.00K  | 1.1K
999999     | 977K   | 977K
1000000    | 977K   | 977K
1000001    | 977K   | 977K
1023999    | 1000K  | 1000K
1024000    | 1000K  | 1000K
1024001    | 1000K  | 1001K
1048575    | 1024K  | 1.0M
1048576    | 1.000M | 1.0M
1048577    | 1.00M  | 1.1M

This was produced with the following invocation:

```
for N in 1 12 123 1234 12345 123456 1234567 12345678 123456789 1234567890 999 1000 1001 1023 1024 1025 999999 1000000 1000001 1023999 1024000 1024001 1048575 1048576 1048577; do
  head -c $N /dev/urandom > r$N
done
./zstd -i1 -b1 -S r1 r12 r123 r1234 r12345 r123456 r1234567 r12345678 r123456789 r1234567890 r999 r1000 r1001 r1023 r1024 r1025 r999999 r1000000 r1000001 r1023999 r1024000 r1024001 r1048575 r1048576 r1048577
```

programs/benchzstd.c
programs/fileio.c
programs/util.c
programs/util.h

index b4c73d73d18205a0d2ceb6098edf08388d5c0631..db051781a5930fa65d10737ee33c46e16284e9fc 100644 (file)
@@ -388,13 +388,13 @@ BMK_benchMemAdvancedNoAlloc(
 #       define NB_MARKS 4
         const char* marks[NB_MARKS] = { " |", " /", " =", " \\" };
         U32 markNb = 0;
-        char inputSizeStr[8]  = "";
-        char outputSizeStr[8] = "";
         int compressionCompleted = (adv->mode == BMK_decodeOnly);
         int decompressionCompleted = (adv->mode == BMK_compressOnly);
         BMK_benchParams_t cbp, dbp;
         BMK_initCCtxArgs cctxprep;
         BMK_initDCtxArgs dctxprep;
+        UTIL_HumanReadableSize_t hr_isize;
+        UTIL_HumanReadableSize_t hr_osize;
 
         cbp.benchFn = local_defaultCompress;   /* ZSTD_compress2 */
         cbp.benchPayload = cctx;
@@ -431,10 +431,10 @@ BMK_benchMemAdvancedNoAlloc(
         dctxprep.dictBuffer = dictBuffer;
         dctxprep.dictBufferSize = dictBufferSize;
 
-        humanSize((unsigned)srcSize, inputSizeStr);
+        hr_isize = UTIL_makeHumanReadableSize((U64) srcSize);
 
         DISPLAYLEVEL(2, "\r%70s\r", "");   /* blank line */
-        DISPLAYLEVEL(2, "%2s-%-17.17s : %s -> \r", marks[markNb], displayName, inputSizeStr);
+        DISPLAYLEVEL(2, "%2s-%-17.17s : %.*f%s -> \r", marks[markNb], displayName, hr_isize.precision, hr_isize.value, hr_isize.suffix);
 
         while (!(compressionCompleted && decompressionCompleted)) {
             if (!compressionCompleted) {
@@ -455,13 +455,11 @@ BMK_benchMemAdvancedNoAlloc(
                 }   }
 
                 {   int const ratioAccuracy = (ratio < 10.) ? 3 : 2;
-
-                    humanSize((unsigned)srcSize, inputSizeStr);
-                    humanSize((unsigned)cSize, outputSizeStr);
-
-                    DISPLAYLEVEL(2, "%2s-%-17.17s : %s -> %s (%5.*f),%6.*f MB/s\r",
+                    hr_osize = UTIL_makeHumanReadableSize((U64) cSize);
+                    DISPLAYLEVEL(2, "%2s-%-17.17s : %.*f%s -> %.*f%s (%5.*f),%6.*f MB/s\r",
                             marks[markNb], displayName,
-                            inputSizeStr, outputSizeStr,
+                            hr_isize.precision, hr_isize.value, hr_isize.suffix,
+                            hr_osize.precision, hr_osize.value, hr_osize.suffix,
                             ratioAccuracy, ratio,
                             benchResult.cSpeed < (10 MB) ? 2 : 1, (double)benchResult.cSpeed / MB_UNIT);
                 }
@@ -482,13 +480,11 @@ BMK_benchMemAdvancedNoAlloc(
                 }
 
                 {   int const ratioAccuracy = (ratio < 10.) ? 3 : 2;
-
-                    humanSize((unsigned)srcSize, inputSizeStr);
-                    humanSize((unsigned)cSize, outputSizeStr);
-
-                    DISPLAYLEVEL(2, "%2s-%-17.17s : %s -> %s (%5.*f),%6.*f MB/s ,%6.1f MB/s \r",
+                    hr_osize = UTIL_makeHumanReadableSize((U64) cSize);
+                    DISPLAYLEVEL(2, "%2s-%-17.17s : %.*f%s -> %.*f%s (%5.*f),%6.*f MB/s ,%6.1f MB/s \r",
                             marks[markNb], displayName,
-                            inputSizeStr, outputSizeStr,
+                            hr_isize.precision, hr_isize.value, hr_isize.suffix,
+                            hr_osize.precision, hr_osize.value, hr_osize.suffix,
                             ratioAccuracy, ratio,
                             benchResult.cSpeed < (10 MB) ? 2 : 1, (double)benchResult.cSpeed / MB_UNIT,
                             (double)benchResult.dSpeed / MB_UNIT);
index cf65c28284e842c68d98438982d6dc571049506b..c83c4fffd8484584ae16bfe02b76b14fd41d9c28 100644 (file)
@@ -1544,9 +1544,6 @@ FIO_compressFilename_internal(FIO_ctx_t* const fCtx,
     U64 readsize = 0;
     U64 compressedfilesize = 0;
     U64 const fileSize = UTIL_getFileSize(srcFileName);
-    char inputSizeStr[8]  = "";
-    char outputSizeStr[8] = "";
-
     DISPLAYLEVEL(5, "%s: %llu bytes \n", srcFileName, (unsigned long long)fileSize);
 
     /* compression format selection */
@@ -1601,13 +1598,14 @@ FIO_compressFilename_internal(FIO_ctx_t* const fCtx,
                 (unsigned long long)readsize, (unsigned long long) compressedfilesize,
                 dstFileName);
         } else {
-            humanSize((unsigned long long) readsize, inputSizeStr);
-            humanSize((unsigned long long) compressedfilesize, outputSizeStr);
+            UTIL_HumanReadableSize_t hr_isize = UTIL_makeHumanReadableSize((U64) readsize);
+            UTIL_HumanReadableSize_t hr_osize = UTIL_makeHumanReadableSize((U64) compressedfilesize);
 
-            DISPLAYLEVEL(2,"%-20s :%6.2f%%   (%s => %s, %s) \n",
+            DISPLAYLEVEL(2,"%-20s :%6.2f%%   (%.*f%s => %.*f%s, %s) \n",
                 srcFileName,
                 (double)compressedfilesize / (double)readsize * 100,
-                inputSizeStr, outputSizeStr,
+                hr_isize.precision, hr_isize.value, hr_isize.suffix,
+                hr_osize.precision, hr_osize.value, hr_osize.suffix,
                 dstFileName);
         }
     }
@@ -1841,8 +1839,6 @@ int FIO_compressMultipleFilenames(FIO_ctx_t* const fCtx,
 {
     int status;
     int error = 0;
-    char inputSizeStr[8]  = "";
-    char outputSizeStr[8] = "";
     cRess_t ress = FIO_createCResources(prefs, dictFileName,
         FIO_getLargestFileSize(inFileNamesTable, (unsigned)fCtx->nbFilesTotal),
         compressionLevel, comprParams);
@@ -1898,13 +1894,15 @@ int FIO_compressMultipleFilenames(FIO_ctx_t* const fCtx,
     }
 
     if (fCtx->nbFilesProcessed >= 1 && fCtx->nbFilesTotal > 1 && fCtx->totalBytesInput != 0) {
-        humanSize((unsigned long long) fCtx->totalBytesInput, inputSizeStr);
-        humanSize((unsigned long long) fCtx->totalBytesOutput, outputSizeStr);
+        UTIL_HumanReadableSize_t hr_isize = UTIL_makeHumanReadableSize((U64) fCtx->totalBytesInput);
+        UTIL_HumanReadableSize_t hr_osize = UTIL_makeHumanReadableSize((U64) fCtx->totalBytesOutput);
 
         DISPLAYLEVEL(2, "\r%79s\r", "");
-        DISPLAYLEVEL(2, "%3d files compressed : %.2f%%   (%s => %s bytes)\n", fCtx->nbFilesProcessed,
+        DISPLAYLEVEL(2, "%3d files compressed : %.2f%%   (%.*f%s => %.*f%s bytes)\n",
+                        fCtx->nbFilesProcessed,
                         (double)fCtx->totalBytesOutput/((double)fCtx->totalBytesInput)*100,
-                        inputSizeStr, outputSizeStr);
+                        hr_isize.precision, hr_isize.value, hr_isize.suffix,
+                        hr_osize.precision, hr_osize.value, hr_osize.suffix);
     }
 
     FIO_freeCResources(&ress);
index 6916139405a70b1323f5c4f7c49ada7c8b8f3b89..347f5cc2f9f5334b186670bf57e456d806414b04 100644 (file)
@@ -121,31 +121,6 @@ int UTIL_requireUserConfirmation(const char* prompt, const char* abortMsg,
 *  Functions
 ***************************************/
 
-/*
- * Take a size in bytes and output a human readable string. Maximum
- * buffer size is 8 but it's usually 7. Example: "123.4G"
-*/
-char* humanSize(unsigned long long size, char* str) {
-    if (size > 1152921504606846976L) {
-        snprintf(str, 7, "%.1fE", (float)size / 1152921504606846976L);
-       } else if (size > 1125899906842624L) {
-        snprintf(str, 7, "%.1fP", (float)size / 1125899906842624L);
-    } else if (size > 1099511627776L) {
-        snprintf(str, 7, "%.1fT", (float)size / 1099511627776L);
-    } else if (size > 1073741824L) {
-        snprintf(str, 7, "%.1fG", (float)size / 1073741824L);
-    } else if (size > 1048576L) {
-        snprintf(str, 7, "%.1fM", (float)size / 1048576L);
-    } else if (size > 1024) {
-        snprintf(str, 7, "%.1fK", (float)size / 1024);
-    } else if (size <= 1024) {
-        snprintf(str, 7, "%uB", (unsigned)size);
-    }
-
-    return str;
-}
-
-
 int UTIL_stat(const char* filename, stat_t* statbuf)
 {
 #if defined(_MSC_VER)
@@ -328,6 +303,43 @@ U64 UTIL_getFileSizeStat(const stat_t* statbuf)
     return (U64)statbuf->st_size;
 }
 
+UTIL_HumanReadableSize_t UTIL_makeHumanReadableSize(U64 size) {
+    UTIL_HumanReadableSize_t hrs;
+    if (size >= (1L << 60)) {
+        hrs.value = (float)size / (1L << 60);
+        hrs.suffix = "E";
+    } else if (size >= (1L << 50)) {
+        hrs.value = (float)size / (1L << 50);
+        hrs.suffix = "P";
+    } else if (size >= (1L << 40)) {
+        hrs.value = (float)size / (1L << 40);
+        hrs.suffix = "T";
+    } else if (size >= (1L << 30)) {
+        hrs.value = (float)size / (1L << 30);
+        hrs.suffix = "G";
+    } else if (size >= (1L << 20)) {
+        hrs.value = (float)size / (1L << 20);
+        hrs.suffix = "M";
+    } else if (size >= (1L << 10)) {
+        hrs.value = (float)size / (1L << 10);
+        hrs.suffix = "K";
+    } else {
+        hrs.value = (float)size;
+        hrs.suffix = "";
+    }
+
+    if (hrs.value >= 100 || (U64)hrs.value == size) {
+        hrs.precision = 0;
+    } else if (hrs.value > 10) {
+        hrs.precision = 1;
+    } else if (hrs.value > 1) {
+        hrs.precision = 2;
+    } else {
+        hrs.precision = 3;
+    }
+
+    return hrs;
+}
 
 U64 UTIL_getTotalFileSize(const char* const * fileNamesTable, unsigned nbFiles)
 {
index ba2ae13c8620bbd57fcec8bab99f1b8c7fbbc675..63cd0c3780590ad94443fa4face748eaa24dcdc9 100644 (file)
@@ -122,11 +122,6 @@ int UTIL_requireUserConfirmation(const char* prompt, const char* abortMsg, const
 #define STRDUP(s) strdup(s)
 #endif
 
-/*
- * Take a size in bytes and output a human readable string. Maximum
- * buffer size is 8 but it's usually 7. Example: "123.4G"
-*/
-char* humanSize(unsigned long long size, char* str);
 
 /**
  * Calls platform's equivalent of stat() on filename and writes info to statbuf.
@@ -176,6 +171,19 @@ int UTIL_isFIFO(const char* infilename);
 U64 UTIL_getFileSize(const char* infilename);
 U64 UTIL_getTotalFileSize(const char* const * fileNamesTable, unsigned nbFiles);
 
+/**
+ * Take a size in bytes and prepare the components to pretty-print it in a
+ * scaled way. The components in the returned struct should be passed in
+ * precision, value, suffix order to a "%.*f%s" format string.
+ */
+typedef struct {
+  float value;
+  int precision;
+  const char* suffix;
+} UTIL_HumanReadableSize_t;
+
+UTIL_HumanReadableSize_t UTIL_makeHumanReadableSize(U64 size);
+
 int UTIL_compareStr(const void *p1, const void *p2);
 const char* UTIL_getFileExtension(const char* infilename);
 void  UTIL_mirrorSourceFilesDirectories(const char** fileNamesTable, unsigned int nbFiles, const char *outDirName);