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