2 This file is part of systemd
4 Copyright 2014 Zbigniew Jędrzejewski-Szmek
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 #include "alloc-util.h"
24 #include "parse-util.h"
25 #include "random-util.h"
26 #include "string-util.h"
29 typedef int (compress_t
)(const void *src
, uint64_t src_size
, void *dst
,
30 size_t dst_alloc_size
, size_t *dst_size
);
31 typedef int (decompress_t
)(const void *src
, uint64_t src_size
,
32 void **dst
, size_t *dst_alloc_size
, size_t* dst_size
, size_t dst_max
);
34 #if HAVE_XZ || HAVE_LZ4
36 static usec_t arg_duration
;
37 static size_t arg_start
;
39 #define MAX_SIZE (1024*1024LU)
40 #define PRIME 1048571 /* A prime close enough to one megabyte that mod 4 == 3 */
42 static size_t _permute(size_t x
) {
48 residue
= x
*x
% PRIME
;
52 return PRIME
- residue
;
55 static size_t permute(size_t x
) {
56 return _permute((_permute(x
) + arg_start
) % MAX_SIZE
^ 0xFF345);
59 static char* make_buf(size_t count
, const char *type
) {
66 if (streq(type
, "zeros"))
68 else if (streq(type
, "simple"))
69 for (i
= 0; i
< count
; i
++)
70 buf
[i
] = 'a' + i
% ('z' - 'a' + 1);
71 else if (streq(type
, "random")) {
72 size_t step
= count
/ 10;
74 random_bytes(buf
, step
);
75 memzero(buf
+ 1*step
, step
);
76 random_bytes(buf
+ 2*step
, step
);
77 memzero(buf
+ 3*step
, step
);
78 random_bytes(buf
+ 4*step
, step
);
79 memzero(buf
+ 5*step
, step
);
80 random_bytes(buf
+ 6*step
, step
);
81 memzero(buf
+ 7*step
, step
);
82 random_bytes(buf
+ 8*step
, step
);
83 memzero(buf
+ 9*step
, step
);
85 assert_not_reached("here");
90 static void test_compress_decompress(const char* label
, const char* type
,
91 compress_t compress
, decompress_t decompress
) {
95 _cleanup_free_
char *text
, *buf
;
96 _cleanup_free_
void *buf2
= NULL
;
97 size_t buf2_allocated
= 0;
98 size_t skipped
= 0, compressed
= 0, total
= 0;
100 text
= make_buf(MAX_SIZE
, type
);
101 buf
= calloc(MAX_SIZE
+ 1, 1);
102 assert_se(text
&& buf
);
104 n
= now(CLOCK_MONOTONIC
);
106 for (size_t i
= 0; i
<= MAX_SIZE
; i
++) {
107 size_t j
= 0, k
= 0, size
;
114 log_debug("%s %zu %zu", type
, i
, size
);
116 memzero(buf
, MIN(size
+ 1000, MAX_SIZE
));
118 r
= compress(text
, size
, buf
, size
, &j
);
119 /* assume compression must be successful except for small or random inputs */
120 assert_se(r
== 0 || (size
< 2048 && r
== -ENOBUFS
) || streq(type
, "random"));
122 /* check for overwrites */
123 assert_se(buf
[size
] == 0);
131 log_error("%s \"compressed\" %zu -> %zu", label
, size
, j
);
133 r
= decompress(buf
, j
, &buf2
, &buf2_allocated
, &k
, 0);
135 assert_se(buf2_allocated
>= k
);
136 assert_se(k
== size
);
138 assert_se(memcmp(text
, buf2
, size
) == 0);
143 n2
= now(CLOCK_MONOTONIC
);
144 if (n2
- n
> arg_duration
)
150 log_info("%s/%s: compressed & decompressed %zu bytes in %.2fs (%.2fMiB/s), "
151 "mean compresion %.2f%%, skipped %zu bytes",
152 label
, type
, total
, dt
,
153 total
/ 1024. / 1024 / dt
,
154 100 - compressed
* 100. / total
,
159 int main(int argc
, char *argv
[]) {
160 #if HAVE_XZ || HAVE_LZ4
164 log_set_max_level(LOG_INFO
);
169 assert_se(safe_atou(argv
[1], &x
) >= 0);
170 arg_duration
= x
* USEC_PER_SEC
;
174 r
= getenv_bool("SYSTEMD_SLOW_TESTS");
175 slow
= r
>= 0 ? r
: SYSTEMD_SLOW_TESTS_DEFAULT
;
177 arg_duration
= slow
? 2 * USEC_PER_SEC
: USEC_PER_SEC
/ 50;
181 (void) safe_atozu(argv
[2], &arg_start
);
183 arg_start
= getpid_cached();
185 NULSTR_FOREACH(i
, "zeros\0simple\0random\0") {
187 test_compress_decompress("XZ", i
, compress_blob_xz
, decompress_blob_xz
);
190 test_compress_decompress("LZ4", i
, compress_blob_lz4
, decompress_blob_lz4
);
195 return EXIT_TEST_SKIP
;