]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
fd53fee0 ZJS |
2 | /*** |
3 | This file is part of systemd | |
4 | ||
5 | Copyright 2014 Zbigniew Jędrzejewski-Szmek | |
6 | ||
7 | systemd is free software; you can redistribute it and/or modify it | |
8 | under the terms of the GNU Lesser General Public License as published by | |
9 | the Free Software Foundation; either version 2.1 of the License, or | |
10 | (at your option) any later version. | |
11 | ||
12 | systemd is distributed in the hope that it will be useful, but | |
13 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 | Lesser General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU Lesser General Public License | |
18 | along with systemd; If not, see <http://www.gnu.org/licenses/>. | |
19 | ***/ | |
20 | ||
b5efdb8a | 21 | #include "alloc-util.h" |
fd53fee0 | 22 | #include "compress.h" |
245d3d3c | 23 | #include "env-util.h" |
fd53fee0 | 24 | #include "macro.h" |
6bedfcbb | 25 | #include "parse-util.h" |
dccca82b | 26 | #include "process-util.h" |
9f35e8b4 | 27 | #include "random-util.h" |
07630cea LP |
28 | #include "string-util.h" |
29 | #include "util.h" | |
fd53fee0 | 30 | |
5d6f46b6 ZJS |
31 | typedef int (compress_t)(const void *src, uint64_t src_size, void *dst, |
32 | size_t dst_alloc_size, size_t *dst_size); | |
fd53fee0 | 33 | typedef int (decompress_t)(const void *src, uint64_t src_size, |
fa1c4b51 | 34 | void **dst, size_t *dst_alloc_size, size_t* dst_size, size_t dst_max); |
fd53fee0 | 35 | |
349cc4a5 | 36 | #if HAVE_XZ || HAVE_LZ4 |
ccc717fa | 37 | |
245d3d3c | 38 | static usec_t arg_duration; |
c4291c15 ZJS |
39 | static size_t arg_start; |
40 | ||
fd53fee0 | 41 | #define MAX_SIZE (1024*1024LU) |
c4291c15 ZJS |
42 | #define PRIME 1048571 /* A prime close enough to one megabyte that mod 4 == 3 */ |
43 | ||
44 | static size_t _permute(size_t x) { | |
45 | size_t residue; | |
46 | ||
47 | if (x >= PRIME) | |
48 | return x; | |
49 | ||
50 | residue = x*x % PRIME; | |
51 | if (x <= PRIME / 2) | |
52 | return residue; | |
53 | else | |
54 | return PRIME - residue; | |
55 | } | |
56 | ||
57 | static size_t permute(size_t x) { | |
58 | return _permute((_permute(x) + arg_start) % MAX_SIZE ^ 0xFF345); | |
59 | } | |
fd53fee0 | 60 | |
9f35e8b4 | 61 | static char* make_buf(size_t count, const char *type) { |
fd53fee0 ZJS |
62 | char *buf; |
63 | size_t i; | |
64 | ||
65 | buf = malloc(count); | |
0c0cdb06 | 66 | assert_se(buf); |
fd53fee0 | 67 | |
9f35e8b4 ZJS |
68 | if (streq(type, "zeros")) |
69 | memzero(buf, count); | |
70 | else if (streq(type, "simple")) | |
71 | for (i = 0; i < count; i++) | |
72 | buf[i] = 'a' + i % ('z' - 'a' + 1); | |
73 | else if (streq(type, "random")) { | |
0036b0bf ZJS |
74 | size_t step = count / 10; |
75 | ||
76 | random_bytes(buf, step); | |
77 | memzero(buf + 1*step, step); | |
78 | random_bytes(buf + 2*step, step); | |
79 | memzero(buf + 3*step, step); | |
80 | random_bytes(buf + 4*step, step); | |
81 | memzero(buf + 5*step, step); | |
82 | random_bytes(buf + 6*step, step); | |
83 | memzero(buf + 7*step, step); | |
84 | random_bytes(buf + 8*step, step); | |
85 | memzero(buf + 9*step, step); | |
9f35e8b4 ZJS |
86 | } else |
87 | assert_not_reached("here"); | |
fd53fee0 ZJS |
88 | |
89 | return buf; | |
90 | } | |
91 | ||
9f35e8b4 | 92 | static void test_compress_decompress(const char* label, const char* type, |
fd53fee0 | 93 | compress_t compress, decompress_t decompress) { |
da2e1c71 | 94 | usec_t n, n2 = 0; |
fd53fee0 ZJS |
95 | float dt; |
96 | ||
97 | _cleanup_free_ char *text, *buf; | |
98 | _cleanup_free_ void *buf2 = NULL; | |
fa1c4b51 | 99 | size_t buf2_allocated = 0; |
fd53fee0 ZJS |
100 | size_t skipped = 0, compressed = 0, total = 0; |
101 | ||
9f35e8b4 | 102 | text = make_buf(MAX_SIZE, type); |
fd53fee0 | 103 | buf = calloc(MAX_SIZE + 1, 1); |
0c0cdb06 | 104 | assert_se(text && buf); |
fd53fee0 ZJS |
105 | |
106 | n = now(CLOCK_MONOTONIC); | |
107 | ||
c4291c15 ZJS |
108 | for (size_t i = 0; i <= MAX_SIZE; i++) { |
109 | size_t j = 0, k = 0, size; | |
fd53fee0 ZJS |
110 | int r; |
111 | ||
c4291c15 | 112 | size = permute(i); |
15b947fb ZJS |
113 | if (size == 0) |
114 | continue; | |
c4291c15 ZJS |
115 | |
116 | log_debug("%s %zu %zu", type, i, size); | |
117 | ||
118 | memzero(buf, MIN(size + 1000, MAX_SIZE)); | |
119 | ||
5d6f46b6 ZJS |
120 | r = compress(text, size, buf, size, &j); |
121 | /* assume compression must be successful except for small or random inputs */ | |
c4291c15 | 122 | assert_se(r == 0 || (size < 2048 && r == -ENOBUFS) || streq(type, "random")); |
9f35e8b4 | 123 | |
fd53fee0 | 124 | /* check for overwrites */ |
c4291c15 | 125 | assert_se(buf[size] == 0); |
fd53fee0 | 126 | if (r != 0) { |
c4291c15 | 127 | skipped += size; |
fd53fee0 ZJS |
128 | continue; |
129 | } | |
130 | ||
0c0cdb06 | 131 | assert_se(j > 0); |
c4291c15 ZJS |
132 | if (j >= size) |
133 | log_error("%s \"compressed\" %zu -> %zu", label, size, j); | |
fd53fee0 ZJS |
134 | |
135 | r = decompress(buf, j, &buf2, &buf2_allocated, &k, 0); | |
0c0cdb06 RC |
136 | assert_se(r == 0); |
137 | assert_se(buf2_allocated >= k); | |
c4291c15 | 138 | assert_se(k == size); |
fd53fee0 | 139 | |
c4291c15 | 140 | assert_se(memcmp(text, buf2, size) == 0); |
fd53fee0 | 141 | |
c4291c15 | 142 | total += size; |
fd53fee0 ZJS |
143 | compressed += j; |
144 | ||
145 | n2 = now(CLOCK_MONOTONIC); | |
c4291c15 | 146 | if (n2 - n > arg_duration) |
fd53fee0 ZJS |
147 | break; |
148 | } | |
149 | ||
150 | dt = (n2-n) / 1e6; | |
151 | ||
9f35e8b4 | 152 | log_info("%s/%s: compressed & decompressed %zu bytes in %.2fs (%.2fMiB/s), " |
fd53fee0 | 153 | "mean compresion %.2f%%, skipped %zu bytes", |
9f35e8b4 | 154 | label, type, total, dt, |
fd53fee0 ZJS |
155 | total / 1024. / 1024 / dt, |
156 | 100 - compressed * 100. / total, | |
157 | skipped); | |
158 | } | |
ccc717fa | 159 | #endif |
fd53fee0 ZJS |
160 | |
161 | int main(int argc, char *argv[]) { | |
349cc4a5 | 162 | #if HAVE_XZ || HAVE_LZ4 |
9f35e8b4 | 163 | const char *i; |
245d3d3c | 164 | int r; |
fd53fee0 | 165 | |
c4291c15 ZJS |
166 | log_set_max_level(LOG_INFO); |
167 | ||
168 | if (argc >= 2) { | |
169 | unsigned x; | |
170 | ||
171 | assert_se(safe_atou(argv[1], &x) >= 0); | |
172 | arg_duration = x * USEC_PER_SEC; | |
245d3d3c ZJS |
173 | } else { |
174 | bool slow; | |
175 | ||
176 | r = getenv_bool("SYSTEMD_SLOW_TESTS"); | |
177 | slow = r >= 0 ? r : SYSTEMD_SLOW_TESTS_DEFAULT; | |
178 | ||
179 | arg_duration = slow ? 2 * USEC_PER_SEC : USEC_PER_SEC / 50; | |
c4291c15 | 180 | } |
245d3d3c | 181 | |
c4291c15 | 182 | if (argc == 3) |
7c2da2ca | 183 | (void) safe_atozu(argv[2], &arg_start); |
c4291c15 | 184 | else |
df0ff127 | 185 | arg_start = getpid_cached(); |
fd53fee0 | 186 | |
9f35e8b4 | 187 | NULSTR_FOREACH(i, "zeros\0simple\0random\0") { |
349cc4a5 | 188 | #if HAVE_XZ |
9f35e8b4 | 189 | test_compress_decompress("XZ", i, compress_blob_xz, decompress_blob_xz); |
fd53fee0 | 190 | #endif |
349cc4a5 | 191 | #if HAVE_LZ4 |
9f35e8b4 | 192 | test_compress_decompress("LZ4", i, compress_blob_lz4, decompress_blob_lz4); |
fd53fee0 | 193 | #endif |
9f35e8b4 | 194 | } |
fd53fee0 | 195 | return 0; |
ccc717fa ZJS |
196 | #else |
197 | return EXIT_TEST_SKIP; | |
198 | #endif | |
fd53fee0 | 199 | } |