Branch data 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 : 200910 : static size_t _permute(size_t x) {
29 : : size_t residue;
30 : :
31 [ + + ]: 200910 : if (x >= PRIME)
32 : 2 : return x;
33 : :
34 : 200908 : residue = x*x % PRIME;
35 [ + + ]: 200908 : if (x <= PRIME / 2)
36 : 146614 : return residue;
37 : : else
38 : 54294 : return PRIME - residue;
39 : : }
40 : :
41 : 100455 : static size_t permute(size_t x) {
42 : 100455 : return _permute((_permute(x) + arg_start) % MAX_SIZE ^ 0xFF345);
43 : : }
44 : :
45 : 24 : static char* make_buf(size_t count, const char *type) {
46 : : char *buf;
47 : : size_t i;
48 : :
49 : 24 : buf = malloc(count);
50 [ - + ]: 24 : assert_se(buf);
51 : :
52 [ + + ]: 24 : if (streq(type, "zeros"))
53 [ + - ]: 8 : memzero(buf, count);
54 [ + + ]: 16 : else if (streq(type, "simple"))
55 [ + + ]: 8388616 : for (i = 0; i < count; i++)
56 : 8388608 : buf[i] = 'a' + i % ('z' - 'a' + 1);
57 [ + - ]: 8 : else if (streq(type, "random")) {
58 : 8 : size_t step = count / 10;
59 : :
60 : 8 : random_bytes(buf, step);
61 [ + - ]: 8 : memzero(buf + 1*step, step);
62 : 8 : random_bytes(buf + 2*step, step);
63 [ + - ]: 8 : memzero(buf + 3*step, step);
64 : 8 : random_bytes(buf + 4*step, step);
65 [ + - ]: 8 : memzero(buf + 5*step, step);
66 : 8 : random_bytes(buf + 6*step, step);
67 [ + - ]: 8 : memzero(buf + 7*step, step);
68 : 8 : random_bytes(buf + 8*step, step);
69 [ + - ]: 8 : memzero(buf + 9*step, step);
70 : : } else
71 : 0 : assert_not_reached("here");
72 : :
73 : 24 : return buf;
74 : : }
75 : :
76 : 24 : static void test_compress_decompress(const char* label, const char* type,
77 : : compress_t compress, decompress_t decompress) {
78 : 24 : usec_t n, n2 = 0;
79 : : float dt;
80 : :
81 : 24 : _cleanup_free_ char *text, *buf;
82 : 48 : _cleanup_free_ void *buf2 = NULL;
83 : 24 : size_t buf2_allocated = 0;
84 : 24 : size_t skipped = 0, compressed = 0, total = 0;
85 : :
86 : 24 : text = make_buf(MAX_SIZE, type);
87 : 24 : buf = calloc(MAX_SIZE + 1, 1);
88 [ + - - + ]: 24 : assert_se(text && buf);
89 : :
90 : 24 : n = now(CLOCK_MONOTONIC);
91 : :
92 [ + - ]: 100455 : for (size_t i = 0; i <= MAX_SIZE; i++) {
93 : 100455 : size_t j = 0, k = 0, size;
94 : : int r;
95 : :
96 : 100455 : size = permute(i);
97 [ - + ]: 100455 : if (size == 0)
98 : 3200 : continue;
99 : :
100 [ - + ]: 100455 : log_debug("%s %zu %zu", type, i, size);
101 : :
102 [ + - ]: 100455 : memzero(buf, MIN(size + 1000, MAX_SIZE));
103 : :
104 : 100455 : r = compress(text, size, buf, size, &j);
105 : : /* assume compression must be successful except for small or random inputs */
106 [ + + + + : 100455 : assert_se(r == 0 || (size < 2048 && r == -ENOBUFS) || streq(type, "random"));
- + + + +
+ - + ]
107 : :
108 : : /* check for overwrites */
109 [ - + ]: 100455 : assert_se(buf[size] == 0);
110 [ + + ]: 100455 : if (r != 0) {
111 : 3200 : skipped += size;
112 : 3200 : continue;
113 : : }
114 : :
115 [ - + ]: 97255 : assert_se(j > 0);
116 [ - + ]: 97255 : if (j >= size)
117 [ # # ]: 0 : log_error("%s \"compressed\" %zu -> %zu", label, size, j);
118 : :
119 : 97255 : r = decompress(buf, j, &buf2, &buf2_allocated, &k, 0);
120 [ - + ]: 97255 : assert_se(r == 0);
121 [ - + ]: 97255 : assert_se(buf2_allocated >= k);
122 [ - + ]: 97255 : assert_se(k == size);
123 : :
124 [ - + ]: 97255 : assert_se(memcmp(text, buf2, size) == 0);
125 : :
126 : 97255 : total += size;
127 : 97255 : compressed += j;
128 : :
129 : 97255 : n2 = now(CLOCK_MONOTONIC);
130 [ + + ]: 97255 : if (n2 - n > arg_duration)
131 : 24 : break;
132 : : }
133 : :
134 : 24 : dt = (n2-n) / 1e6;
135 : :
136 [ + - ]: 24 : 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 : 24 : }
143 : : #endif
144 : :
145 : 4 : int main(int argc, char *argv[]) {
146 : : #if HAVE_XZ || HAVE_LZ4
147 : 4 : test_setup_logging(LOG_INFO);
148 : :
149 [ - + ]: 4 : 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 : 8 : arg_duration = slow_tests_enabled() ?
156 [ + - ]: 4 : 2 * USEC_PER_SEC : USEC_PER_SEC / 50;
157 : :
158 [ - + ]: 4 : if (argc == 3)
159 : 0 : (void) safe_atozu(argv[2], &arg_start);
160 : : else
161 : 4 : arg_start = getpid_cached();
162 : :
163 : : const char *i;
164 [ + - + + ]: 16 : NULSTR_FOREACH(i, "zeros\0simple\0random\0") {
165 : : #if HAVE_XZ
166 : 12 : test_compress_decompress("XZ", i, compress_blob_xz, decompress_blob_xz);
167 : : #endif
168 : : #if HAVE_LZ4
169 : 12 : test_compress_decompress("LZ4", i, compress_blob_lz4, decompress_blob_lz4);
170 : : #endif
171 : : }
172 : 4 : return 0;
173 : : #else
174 : : return log_tests_skipped("No compression feature is enabled");
175 : : #endif
176 : : }
|