3 * Copyright (c) 2022 Samsung Electronics Co., Ltd.
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is furnished
10 * to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in all
13 * copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
30 #include "logcommon.h"
31 #include "test_compression_common.h"
32 #include "fastlz_test.h"
34 // The strings to compress.
35 static const char *const repeated_string = "Did you ever hear the tragedy of darth plagueis the wise?";
36 static const char *const fuzzable_string = "Ala ma kota";
37 static const char *const garbage_string = "fdffdfdfddfdfdfdd";
39 void modify_one_letter(char *str, size_t size)
41 str[rand() % size] = 'a' + rand() % 26;
44 void copy_string_repeatedly(char *in, size_t size, const char *source, bool apply_fuzzing)
46 const size_t source_len = strlen(source);
47 const size_t repeats = size / source_len;
49 for (size_t i = 0; i < repeats; ++i) {
50 memcpy(in + i * source_len, source, source_len);
52 modify_one_letter(in + i * source_len, source_len);
56 void gen_zeroes(char *in, size_t size)
58 for (size_t i = 0; i < size; ++i)
62 void gen_alpha(char *in, size_t size)
64 for (size_t i = 0; i < size; ++i)
65 in[i] = 'a' + rand() % 26;
68 void gen_01(char *in, size_t size)
70 /* Produce something like 010100101000111...
71 * Note that the algorithm works at the level
72 * of bytes, not bits, so these being mostly
73 * composed of zero-bits doesn't matter much. */
74 for (size_t i = 0; i < size; ++i)
78 void gen_repeated_string(char *in, size_t size)
80 /* Generates a pattern of a repeated string,
81 * disrupted near the end by garbage (RRRRRRGR) */
83 gen_zeroes(in, size); // for strcat
85 const size_t extras = strlen(garbage_string) + strlen(repeated_string) + sizeof '\0';
86 assert(size >= extras);
88 copy_string_repeatedly(in, size - extras, repeated_string, false);
89 strcat(in, garbage_string);
90 strcat(in, repeated_string);
93 void gen_fuzzy_string(char *in, size_t size)
95 /* Generates a slightly corrupted pattern.
96 * For example with the base of "Ala ma kota":
107 const size_t fuzzable_len = strlen(fuzzable_string);
108 gen_zeroes(in + size - fuzzable_len, fuzzable_len); // the pattern won't fit perfectly
110 copy_string_repeatedly(in, size, fuzzable_string, true);
113 void gen_weighted_alpha(char *in, size_t size)
115 /* Produce a random string with letters weighted
116 * by their ~actual English frequencies. */
117 static const struct letter {
147 size_t total = 0; // ideally this would be compile-time but we're not C++
148 for (size_t i = 0; i < NELEMS(letters); ++i)
149 total += letters[i].freq;
151 for (size_t i = 0; i < size; ++i) {
152 int rnd = rand() % total;
154 while (rnd > letters[j].freq) {
155 rnd -= letters[j].freq;
158 in[i] = letters[j].letter;
162 typedef void (*generator_t)(char *, size_t);
163 void test_via_generator(generator_t gen, size_t size, const struct test_algo *algo, const char *algo_name, const char *gen_name)
165 char *const in = malloc(size);
169 struct common_compressed *out;
170 struct timespec ts_comp = algo->comp(in, size, &out);
171 assert(out->size_compressed);
173 const size_t comp_size = out->size_compressed;
177 struct timespec ts_decomp = algo->decomp(out, &re, &re_size);
179 for (size_t i = 0; i < re_size; ++i)
180 assert(re[i] == in[i]);
184 multiply_timespec(&ts_comp , (double) MSEC_PER_SEC / ACTUAL_CALLS);
185 multiply_timespec(&ts_decomp, (double) MSEC_PER_SEC / ACTUAL_CALLS);
187 printf("%s / %s / %zu\n"
188 "\t compressed in %d.%02dms\n"
189 "\tdecompressed in %d.%02dms\n"
190 "\tcompressed into %zu bytes (%.1f%%)\n"
191 , algo_name, gen_name, size
192 , (int) ts_comp.tv_sec, (int) ts_comp.tv_nsec / (NSEC_PER_SEC / 100)
193 , (int) ts_decomp.tv_sec, (int) ts_decomp.tv_nsec / (NSEC_PER_SEC / 100)
194 , comp_size, 100.f * comp_size / size
201 /* NB: The following tests fails when ASAN is enabled, with a supposed memory
202 * violation in fastlz. This does not spark joy and we should probably fix this.
203 * Hovever, we have more urgent things to do right now, so let's disable
204 * the test on ASAN for now. */
207 #endif /* ASAN_BUILD */
209 static const int sizes[] = {
210 4096, // max single log payload
211 65530, // just below 2^16, which may be a behaviour change threshold for some algos
212 65540, // just above 2^16
213 131072, // the size of the buffer used by dlog_logger
216 static const struct {
217 const struct test_algo *algo;
220 #define A(x) { .algo = &x, .name = #x }
225 static const struct {
226 const generator_t gen;
229 #define G(x) { .gen = gen_ ## x, .name = #x }
239 for (size_t s = 0; s < NELEMS(sizes); ++s)
240 for (size_t g = 0; g < NELEMS(gens); ++g)
241 for (size_t a = 0; a < NELEMS(algos); ++a)
242 test_via_generator(gens[g].gen, sizes[s], algos[a].algo, algos[a].name, gens[g].name);