LCOV - code coverage report
Current view: top level - journal - test-compress-benchmark.c (source / functions) Hit Total Coverage
Test: main_coverage.info Lines: 78 84 92.9 %
Date: 2019-08-22 15:41:25 Functions: 5 5 100.0 %

          Line data    Source code
       1             : /* SPDX-License-Identifier: LGPL-2.1+ */
       2             : 
       3             : #include "alloc-util.h"
       4             : #include "compress.h"
       5             : #include "env-util.h"
       6             : #include "macro.h"
       7             : #include "memory-util.h"
       8             : #include "nulstr-util.h"
       9             : #include "parse-util.h"
      10             : #include "process-util.h"
      11             : #include "random-util.h"
      12             : #include "string-util.h"
      13             : #include "tests.h"
      14             : 
      15             : typedef int (compress_t)(const void *src, uint64_t src_size, void *dst,
      16             :                          size_t dst_alloc_size, size_t *dst_size);
      17             : typedef int (decompress_t)(const void *src, uint64_t src_size,
      18             :                            void **dst, size_t *dst_alloc_size, size_t* dst_size, size_t dst_max);
      19             : 
      20             : #if HAVE_XZ || HAVE_LZ4
      21             : 
      22             : static usec_t arg_duration;
      23             : static size_t arg_start;
      24             : 
      25             : #define MAX_SIZE (1024*1024LU)
      26             : #define PRIME 1048571  /* A prime close enough to one megabyte that mod 4 == 3 */
      27             : 
      28         538 : static size_t _permute(size_t x) {
      29             :         size_t residue;
      30             : 
      31         538 :         if (x >= PRIME)
      32           0 :                 return x;
      33             : 
      34         538 :         residue = x*x % PRIME;
      35         538 :         if (x <= PRIME / 2)
      36         269 :                 return residue;
      37             :         else
      38         269 :                 return PRIME - residue;
      39             : }
      40             : 
      41         269 : static size_t permute(size_t x) {
      42         269 :         return _permute((_permute(x) + arg_start) % MAX_SIZE ^ 0xFF345);
      43             : }
      44             : 
      45           6 : static char* make_buf(size_t count, const char *type) {
      46             :         char *buf;
      47             :         size_t i;
      48             : 
      49           6 :         buf = malloc(count);
      50           6 :         assert_se(buf);
      51             : 
      52           6 :         if (streq(type, "zeros"))
      53           2 :                 memzero(buf, count);
      54           4 :         else if (streq(type, "simple"))
      55     2097154 :                 for (i = 0; i < count; i++)
      56     2097152 :                         buf[i] = 'a' + i % ('z' - 'a' + 1);
      57           2 :         else if (streq(type, "random")) {
      58           2 :                 size_t step = count / 10;
      59             : 
      60           2 :                 random_bytes(buf, step);
      61           2 :                 memzero(buf + 1*step, step);
      62           2 :                 random_bytes(buf + 2*step, step);
      63           2 :                 memzero(buf + 3*step, step);
      64           2 :                 random_bytes(buf + 4*step, step);
      65           2 :                 memzero(buf + 5*step, step);
      66           2 :                 random_bytes(buf + 6*step, step);
      67           2 :                 memzero(buf + 7*step, step);
      68           2 :                 random_bytes(buf + 8*step, step);
      69           2 :                 memzero(buf + 9*step, step);
      70             :         } else
      71           0 :                 assert_not_reached("here");
      72             : 
      73           6 :         return buf;
      74             : }
      75             : 
      76           6 : static void test_compress_decompress(const char* label, const char* type,
      77             :                                      compress_t compress, decompress_t decompress) {
      78           6 :         usec_t n, n2 = 0;
      79             :         float dt;
      80             : 
      81           6 :         _cleanup_free_ char *text, *buf;
      82          12 :         _cleanup_free_ void *buf2 = NULL;
      83           6 :         size_t buf2_allocated = 0;
      84           6 :         size_t skipped = 0, compressed = 0, total = 0;
      85             : 
      86           6 :         text = make_buf(MAX_SIZE, type);
      87           6 :         buf = calloc(MAX_SIZE + 1, 1);
      88           6 :         assert_se(text && buf);
      89             : 
      90           6 :         n = now(CLOCK_MONOTONIC);
      91             : 
      92         269 :         for (size_t i = 0; i <= MAX_SIZE; i++) {
      93         269 :                 size_t j = 0, k = 0, size;
      94             :                 int r;
      95             : 
      96         269 :                 size = permute(i);
      97         269 :                 if (size == 0)
      98           9 :                         continue;
      99             : 
     100         269 :                 log_debug("%s %zu %zu", type, i, size);
     101             : 
     102         269 :                 memzero(buf, MIN(size + 1000, MAX_SIZE));
     103             : 
     104         269 :                 r = compress(text, size, buf, size, &j);
     105             :                 /* assume compression must be successful except for small or random inputs */
     106         269 :                 assert_se(r == 0 || (size < 2048 && r == -ENOBUFS) || streq(type, "random"));
     107             : 
     108             :                 /* check for overwrites */
     109         269 :                 assert_se(buf[size] == 0);
     110         269 :                 if (r != 0) {
     111           9 :                         skipped += size;
     112           9 :                         continue;
     113             :                 }
     114             : 
     115         260 :                 assert_se(j > 0);
     116         260 :                 if (j >= size)
     117           0 :                         log_error("%s \"compressed\" %zu -> %zu", label, size, j);
     118             : 
     119         260 :                 r = decompress(buf, j, &buf2, &buf2_allocated, &k, 0);
     120         260 :                 assert_se(r == 0);
     121         260 :                 assert_se(buf2_allocated >= k);
     122         260 :                 assert_se(k == size);
     123             : 
     124         260 :                 assert_se(memcmp(text, buf2, size) == 0);
     125             : 
     126         260 :                 total += size;
     127         260 :                 compressed += j;
     128             : 
     129         260 :                 n2 = now(CLOCK_MONOTONIC);
     130         260 :                 if (n2 - n > arg_duration)
     131           6 :                         break;
     132             :         }
     133             : 
     134           6 :         dt = (n2-n) / 1e6;
     135             : 
     136           6 :         log_info("%s/%s: compressed & decompressed %zu bytes in %.2fs (%.2fMiB/s), "
     137             :                  "mean compression %.2f%%, skipped %zu bytes",
     138             :                  label, type, total, dt,
     139             :                  total / 1024. / 1024 / dt,
     140             :                  100 - compressed * 100. / total,
     141             :                  skipped);
     142           6 : }
     143             : #endif
     144             : 
     145           1 : int main(int argc, char *argv[]) {
     146             : #if HAVE_XZ || HAVE_LZ4
     147           1 :         test_setup_logging(LOG_INFO);
     148             : 
     149           1 :         if (argc >= 2) {
     150             :                 unsigned x;
     151             : 
     152           0 :                 assert_se(safe_atou(argv[1], &x) >= 0);
     153           0 :                 arg_duration = x * USEC_PER_SEC;
     154             :         } else
     155           2 :                 arg_duration = slow_tests_enabled() ?
     156           1 :                         2 * USEC_PER_SEC : USEC_PER_SEC / 50;
     157             : 
     158           1 :         if (argc == 3)
     159           0 :                 (void) safe_atozu(argv[2], &arg_start);
     160             :         else
     161           1 :                 arg_start = getpid_cached();
     162             : 
     163             :         const char *i;
     164           4 :         NULSTR_FOREACH(i, "zeros\0simple\0random\0") {
     165             : #if HAVE_XZ
     166           3 :                 test_compress_decompress("XZ", i, compress_blob_xz, decompress_blob_xz);
     167             : #endif
     168             : #if HAVE_LZ4
     169           3 :                 test_compress_decompress("LZ4", i, compress_blob_lz4, decompress_blob_lz4);
     170             : #endif
     171             :         }
     172           1 :         return 0;
     173             : #else
     174             :         return log_tests_skipped("No compression feature is enabled");
     175             : #endif
     176             : }

Generated by: LCOV version 1.14