]>
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" |
9f35e8b4 | 26 | #include "random-util.h" |
07630cea LP |
27 | #include "string-util.h" |
28 | #include "util.h" | |
fd53fee0 | 29 | |
5d6f46b6 ZJS |
30 | typedef int (compress_t)(const void *src, uint64_t src_size, void *dst, |
31 | size_t dst_alloc_size, size_t *dst_size); | |
fd53fee0 | 32 | typedef int (decompress_t)(const void *src, uint64_t src_size, |
fa1c4b51 | 33 | void **dst, size_t *dst_alloc_size, size_t* dst_size, size_t dst_max); |
fd53fee0 | 34 | |
349cc4a5 | 35 | #if HAVE_XZ || HAVE_LZ4 |
ccc717fa | 36 | |
245d3d3c | 37 | static usec_t arg_duration; |
c4291c15 ZJS |
38 | static size_t arg_start; |
39 | ||
fd53fee0 | 40 | #define MAX_SIZE (1024*1024LU) |
c4291c15 ZJS |
41 | #define PRIME 1048571 /* A prime close enough to one megabyte that mod 4 == 3 */ |
42 | ||
43 | static size_t _permute(size_t x) { | |
44 | size_t residue; | |
45 | ||
46 | if (x >= PRIME) | |
47 | return x; | |
48 | ||
49 | residue = x*x % PRIME; | |
50 | if (x <= PRIME / 2) | |
51 | return residue; | |
52 | else | |
53 | return PRIME - residue; | |
54 | } | |
55 | ||
56 | static size_t permute(size_t x) { | |
57 | return _permute((_permute(x) + arg_start) % MAX_SIZE ^ 0xFF345); | |
58 | } | |
fd53fee0 | 59 | |
9f35e8b4 | 60 | static char* make_buf(size_t count, const char *type) { |
fd53fee0 ZJS |
61 | char *buf; |
62 | size_t i; | |
63 | ||
64 | buf = malloc(count); | |
0c0cdb06 | 65 | assert_se(buf); |
fd53fee0 | 66 | |
9f35e8b4 ZJS |
67 | if (streq(type, "zeros")) |
68 | memzero(buf, count); | |
69 | else if (streq(type, "simple")) | |
70 | for (i = 0; i < count; i++) | |
71 | buf[i] = 'a' + i % ('z' - 'a' + 1); | |
72 | else if (streq(type, "random")) { | |
0036b0bf ZJS |
73 | size_t step = count / 10; |
74 | ||
75 | random_bytes(buf, step); | |
76 | memzero(buf + 1*step, step); | |
77 | random_bytes(buf + 2*step, step); | |
78 | memzero(buf + 3*step, step); | |
79 | random_bytes(buf + 4*step, step); | |
80 | memzero(buf + 5*step, step); | |
81 | random_bytes(buf + 6*step, step); | |
82 | memzero(buf + 7*step, step); | |
83 | random_bytes(buf + 8*step, step); | |
84 | memzero(buf + 9*step, step); | |
9f35e8b4 ZJS |
85 | } else |
86 | assert_not_reached("here"); | |
fd53fee0 ZJS |
87 | |
88 | return buf; | |
89 | } | |
90 | ||
9f35e8b4 | 91 | static void test_compress_decompress(const char* label, const char* type, |
fd53fee0 | 92 | compress_t compress, decompress_t decompress) { |
da2e1c71 | 93 | usec_t n, n2 = 0; |
fd53fee0 ZJS |
94 | float dt; |
95 | ||
96 | _cleanup_free_ char *text, *buf; | |
97 | _cleanup_free_ void *buf2 = NULL; | |
fa1c4b51 | 98 | size_t buf2_allocated = 0; |
fd53fee0 ZJS |
99 | size_t skipped = 0, compressed = 0, total = 0; |
100 | ||
9f35e8b4 | 101 | text = make_buf(MAX_SIZE, type); |
fd53fee0 | 102 | buf = calloc(MAX_SIZE + 1, 1); |
0c0cdb06 | 103 | assert_se(text && buf); |
fd53fee0 ZJS |
104 | |
105 | n = now(CLOCK_MONOTONIC); | |
106 | ||
c4291c15 ZJS |
107 | for (size_t i = 0; i <= MAX_SIZE; i++) { |
108 | size_t j = 0, k = 0, size; | |
fd53fee0 ZJS |
109 | int r; |
110 | ||
c4291c15 | 111 | size = permute(i); |
15b947fb ZJS |
112 | if (size == 0) |
113 | continue; | |
c4291c15 ZJS |
114 | |
115 | log_debug("%s %zu %zu", type, i, size); | |
116 | ||
117 | memzero(buf, MIN(size + 1000, MAX_SIZE)); | |
118 | ||
5d6f46b6 ZJS |
119 | r = compress(text, size, buf, size, &j); |
120 | /* assume compression must be successful except for small or random inputs */ | |
c4291c15 | 121 | assert_se(r == 0 || (size < 2048 && r == -ENOBUFS) || streq(type, "random")); |
9f35e8b4 | 122 | |
fd53fee0 | 123 | /* check for overwrites */ |
c4291c15 | 124 | assert_se(buf[size] == 0); |
fd53fee0 | 125 | if (r != 0) { |
c4291c15 | 126 | skipped += size; |
fd53fee0 ZJS |
127 | continue; |
128 | } | |
129 | ||
0c0cdb06 | 130 | assert_se(j > 0); |
c4291c15 ZJS |
131 | if (j >= size) |
132 | log_error("%s \"compressed\" %zu -> %zu", label, size, j); | |
fd53fee0 ZJS |
133 | |
134 | r = decompress(buf, j, &buf2, &buf2_allocated, &k, 0); | |
0c0cdb06 RC |
135 | assert_se(r == 0); |
136 | assert_se(buf2_allocated >= k); | |
c4291c15 | 137 | assert_se(k == size); |
fd53fee0 | 138 | |
c4291c15 | 139 | assert_se(memcmp(text, buf2, size) == 0); |
fd53fee0 | 140 | |
c4291c15 | 141 | total += size; |
fd53fee0 ZJS |
142 | compressed += j; |
143 | ||
144 | n2 = now(CLOCK_MONOTONIC); | |
c4291c15 | 145 | if (n2 - n > arg_duration) |
fd53fee0 ZJS |
146 | break; |
147 | } | |
148 | ||
149 | dt = (n2-n) / 1e6; | |
150 | ||
9f35e8b4 | 151 | log_info("%s/%s: compressed & decompressed %zu bytes in %.2fs (%.2fMiB/s), " |
fd53fee0 | 152 | "mean compresion %.2f%%, skipped %zu bytes", |
9f35e8b4 | 153 | label, type, total, dt, |
fd53fee0 ZJS |
154 | total / 1024. / 1024 / dt, |
155 | 100 - compressed * 100. / total, | |
156 | skipped); | |
157 | } | |
ccc717fa | 158 | #endif |
fd53fee0 ZJS |
159 | |
160 | int main(int argc, char *argv[]) { | |
349cc4a5 | 161 | #if HAVE_XZ || HAVE_LZ4 |
9f35e8b4 | 162 | const char *i; |
245d3d3c | 163 | int r; |
fd53fee0 | 164 | |
c4291c15 ZJS |
165 | log_set_max_level(LOG_INFO); |
166 | ||
167 | if (argc >= 2) { | |
168 | unsigned x; | |
169 | ||
170 | assert_se(safe_atou(argv[1], &x) >= 0); | |
171 | arg_duration = x * USEC_PER_SEC; | |
245d3d3c ZJS |
172 | } else { |
173 | bool slow; | |
174 | ||
175 | r = getenv_bool("SYSTEMD_SLOW_TESTS"); | |
176 | slow = r >= 0 ? r : SYSTEMD_SLOW_TESTS_DEFAULT; | |
177 | ||
178 | arg_duration = slow ? 2 * USEC_PER_SEC : USEC_PER_SEC / 50; | |
c4291c15 | 179 | } |
245d3d3c | 180 | |
c4291c15 | 181 | if (argc == 3) |
7c2da2ca | 182 | (void) safe_atozu(argv[2], &arg_start); |
c4291c15 | 183 | else |
df0ff127 | 184 | arg_start = getpid_cached(); |
fd53fee0 | 185 | |
9f35e8b4 | 186 | NULSTR_FOREACH(i, "zeros\0simple\0random\0") { |
349cc4a5 | 187 | #if HAVE_XZ |
9f35e8b4 | 188 | test_compress_decompress("XZ", i, compress_blob_xz, decompress_blob_xz); |
fd53fee0 | 189 | #endif |
349cc4a5 | 190 | #if HAVE_LZ4 |
9f35e8b4 | 191 | test_compress_decompress("LZ4", i, compress_blob_lz4, decompress_blob_lz4); |
fd53fee0 | 192 | #endif |
9f35e8b4 | 193 | } |
fd53fee0 | 194 | return 0; |
ccc717fa ZJS |
195 | #else |
196 | return EXIT_TEST_SKIP; | |
197 | #endif | |
fd53fee0 | 198 | } |