1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright © 2014 Zbigniew Jędrzejewski-Szmek
6 #include "alloc-util.h"
10 #include "parse-util.h"
11 #include "process-util.h"
12 #include "random-util.h"
13 #include "string-util.h"
16 typedef int (compress_t
)(const void *src
, uint64_t src_size
, void *dst
,
17 size_t dst_alloc_size
, size_t *dst_size
);
18 typedef int (decompress_t
)(const void *src
, uint64_t src_size
,
19 void **dst
, size_t *dst_alloc_size
, size_t* dst_size
, size_t dst_max
);
21 #if HAVE_XZ || HAVE_LZ4
23 static usec_t arg_duration
;
24 static size_t arg_start
;
26 #define MAX_SIZE (1024*1024LU)
27 #define PRIME 1048571 /* A prime close enough to one megabyte that mod 4 == 3 */
29 static size_t _permute(size_t x
) {
35 residue
= x
*x
% PRIME
;
39 return PRIME
- residue
;
42 static size_t permute(size_t x
) {
43 return _permute((_permute(x
) + arg_start
) % MAX_SIZE
^ 0xFF345);
46 static char* make_buf(size_t count
, const char *type
) {
53 if (streq(type
, "zeros"))
55 else if (streq(type
, "simple"))
56 for (i
= 0; i
< count
; i
++)
57 buf
[i
] = 'a' + i
% ('z' - 'a' + 1);
58 else if (streq(type
, "random")) {
59 size_t step
= count
/ 10;
61 random_bytes(buf
, step
);
62 memzero(buf
+ 1*step
, step
);
63 random_bytes(buf
+ 2*step
, step
);
64 memzero(buf
+ 3*step
, step
);
65 random_bytes(buf
+ 4*step
, step
);
66 memzero(buf
+ 5*step
, step
);
67 random_bytes(buf
+ 6*step
, step
);
68 memzero(buf
+ 7*step
, step
);
69 random_bytes(buf
+ 8*step
, step
);
70 memzero(buf
+ 9*step
, step
);
72 assert_not_reached("here");
77 static void test_compress_decompress(const char* label
, const char* type
,
78 compress_t compress
, decompress_t decompress
) {
82 _cleanup_free_
char *text
, *buf
;
83 _cleanup_free_
void *buf2
= NULL
;
84 size_t buf2_allocated
= 0;
85 size_t skipped
= 0, compressed
= 0, total
= 0;
87 text
= make_buf(MAX_SIZE
, type
);
88 buf
= calloc(MAX_SIZE
+ 1, 1);
89 assert_se(text
&& buf
);
91 n
= now(CLOCK_MONOTONIC
);
93 for (size_t i
= 0; i
<= MAX_SIZE
; i
++) {
94 size_t j
= 0, k
= 0, size
;
101 log_debug("%s %zu %zu", type
, i
, size
);
103 memzero(buf
, MIN(size
+ 1000, MAX_SIZE
));
105 r
= compress(text
, size
, buf
, size
, &j
);
106 /* assume compression must be successful except for small or random inputs */
107 assert_se(r
== 0 || (size
< 2048 && r
== -ENOBUFS
) || streq(type
, "random"));
109 /* check for overwrites */
110 assert_se(buf
[size
] == 0);
118 log_error("%s \"compressed\" %zu -> %zu", label
, size
, j
);
120 r
= decompress(buf
, j
, &buf2
, &buf2_allocated
, &k
, 0);
122 assert_se(buf2_allocated
>= k
);
123 assert_se(k
== size
);
125 assert_se(memcmp(text
, buf2
, size
) == 0);
130 n2
= now(CLOCK_MONOTONIC
);
131 if (n2
- n
> arg_duration
)
137 log_info("%s/%s: compressed & decompressed %zu bytes in %.2fs (%.2fMiB/s), "
138 "mean compresion %.2f%%, skipped %zu bytes",
139 label
, type
, total
, dt
,
140 total
/ 1024. / 1024 / dt
,
141 100 - compressed
* 100. / total
,
146 int main(int argc
, char *argv
[]) {
147 #if HAVE_XZ || HAVE_LZ4
151 log_set_max_level(LOG_INFO
);
156 assert_se(safe_atou(argv
[1], &x
) >= 0);
157 arg_duration
= x
* USEC_PER_SEC
;
161 r
= getenv_bool("SYSTEMD_SLOW_TESTS");
162 slow
= r
>= 0 ? r
: SYSTEMD_SLOW_TESTS_DEFAULT
;
164 arg_duration
= slow
? 2 * USEC_PER_SEC
: USEC_PER_SEC
/ 50;
168 (void) safe_atozu(argv
[2], &arg_start
);
170 arg_start
= getpid_cached();
172 NULSTR_FOREACH(i
, "zeros\0simple\0random\0") {
174 test_compress_decompress("XZ", i
, compress_blob_xz
, decompress_blob_xz
);
177 test_compress_decompress("LZ4", i
, compress_blob_lz4
, decompress_blob_lz4
);
182 return EXIT_TEST_SKIP
;