]> git.proxmox.com Git - ceph.git/blame - ceph/src/test/compressor/test_compression.cc
import 15.2.0 Octopus source
[ceph.git] / ceph / src / test / compressor / test_compression.cc
CommitLineData
7c673cae
FG
1// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
2// vim: ts=8 sw=2 smarttab
3/*
4 * Ceph distributed storage system
5 *
6 * Copyright (C) 2015 Mirantis, Inc.
7 *
8 * Author: Alyona Kiseleva <akiselyova@mirantis.com>
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 */
16
17#include <errno.h>
18#include <signal.h>
19#include <stdlib.h>
20#include "gtest/gtest.h"
11fdf7f2 21#include "common/ceph_context.h"
7c673cae
FG
22#include "common/config.h"
23#include "compressor/Compressor.h"
24#include "compressor/CompressionPlugin.h"
25#include "global/global_context.h"
9f95a23c 26#include "osd/OSDMap.h"
7c673cae
FG
27
28class CompressorTest : public ::testing::Test,
29 public ::testing::WithParamInterface<const char*> {
30public:
31 std::string plugin;
32 CompressorRef compressor;
33 bool old_zlib_isal;
34
35 CompressorTest() {
36 // note for later
11fdf7f2 37 old_zlib_isal = g_conf()->compressor_zlib_isal;
7c673cae
FG
38
39 plugin = GetParam();
40 size_t pos = plugin.find('/');
41 if (pos != std::string::npos) {
42 string isal = plugin.substr(pos + 1);
43 plugin = plugin.substr(0, pos);
44 if (isal == "isal") {
11fdf7f2
TL
45 g_conf().set_val("compressor_zlib_isal", "true");
46 g_ceph_context->_conf.apply_changes(nullptr);
7c673cae 47 } else if (isal == "noisal") {
11fdf7f2
TL
48 g_conf().set_val("compressor_zlib_isal", "false");
49 g_ceph_context->_conf.apply_changes(nullptr);
7c673cae 50 } else {
11fdf7f2 51 ceph_abort_msg("bad option");
7c673cae
FG
52 }
53 }
54 cout << "[plugin " << plugin << " (" << GetParam() << ")]" << std::endl;
55 }
56 ~CompressorTest() override {
11fdf7f2
TL
57 g_conf().set_val("compressor_zlib_isal", old_zlib_isal ? "true" : "false");
58 g_ceph_context->_conf.apply_changes(nullptr);
7c673cae
FG
59 }
60
61 void SetUp() override {
62 compressor = Compressor::create(g_ceph_context, plugin);
63 ASSERT_TRUE(compressor);
64 }
65 void TearDown() override {
66 compressor.reset();
67 }
68};
69
70TEST_P(CompressorTest, load_plugin)
71{
72}
73
74TEST_P(CompressorTest, small_round_trip)
75{
76 bufferlist orig;
77 orig.append("This is a short string. There are many strings like it but this one is mine.");
78 bufferlist compressed;
79 int r = compressor->compress(orig, compressed);
80 ASSERT_EQ(0, r);
81 bufferlist decompressed;
82 r = compressor->decompress(compressed, decompressed);
83 ASSERT_EQ(0, r);
84 ASSERT_EQ(decompressed.length(), orig.length());
85 ASSERT_TRUE(decompressed.contents_equal(orig));
86 cout << "orig " << orig.length() << " compressed " << compressed.length()
87 << " with " << GetParam() << std::endl;
88}
89
90TEST_P(CompressorTest, big_round_trip_repeated)
91{
92 unsigned len = 1048576 * 4;
93 bufferlist orig;
94 while (orig.length() < len) {
95 orig.append("This is a short string. There are many strings like it but this one is mine.");
96 }
97 bufferlist compressed;
98 int r = compressor->compress(orig, compressed);
99 ASSERT_EQ(0, r);
100 bufferlist decompressed;
101 r = compressor->decompress(compressed, decompressed);
102 ASSERT_EQ(0, r);
103 ASSERT_EQ(decompressed.length(), orig.length());
104 ASSERT_TRUE(decompressed.contents_equal(orig));
105 cout << "orig " << orig.length() << " compressed " << compressed.length()
106 << " with " << GetParam() << std::endl;
107}
108
109TEST_P(CompressorTest, big_round_trip_randomish)
110{
c07f9fc5 111 unsigned len = 1048576 * 10;//269;
7c673cae
FG
112 bufferlist orig;
113 const char *alphabet = "abcdefghijklmnopqrstuvwxyz";
114 if (false) {
115 while (orig.length() < len) {
116 orig.append(alphabet[rand() % 10]);
117 }
118 } else {
119 bufferptr bp(len);
120 char *p = bp.c_str();
121 for (unsigned i=0; i<len; ++i) {
122 p[i] = alphabet[rand() % 10];
123 }
124 orig.append(bp);
125 }
126 bufferlist compressed;
127 int r = compressor->compress(orig, compressed);
128 ASSERT_EQ(0, r);
129 bufferlist decompressed;
130 r = compressor->decompress(compressed, decompressed);
131 ASSERT_EQ(0, r);
132 ASSERT_EQ(decompressed.length(), orig.length());
133 ASSERT_TRUE(decompressed.contents_equal(orig));
134 cout << "orig " << orig.length() << " compressed " << compressed.length()
135 << " with " << GetParam() << std::endl;
136}
137
138#if 0
139TEST_P(CompressorTest, big_round_trip_file)
140{
141 bufferlist orig;
142 int fd = ::open("bin/ceph-osd", O_RDONLY);
143 struct stat st;
144 ::fstat(fd, &st);
145 orig.read_fd(fd, st.st_size);
146
147 bufferlist compressed;
148 int r = compressor->compress(orig, compressed);
149 ASSERT_EQ(0, r);
150 bufferlist decompressed;
151 r = compressor->decompress(compressed, decompressed);
152 ASSERT_EQ(0, r);
153 ASSERT_EQ(decompressed.length(), orig.length());
154 ASSERT_TRUE(decompressed.contents_equal(orig));
155 cout << "orig " << orig.length() << " compressed " << compressed.length()
156 << " with " << GetParam() << std::endl;
157}
158#endif
159
160
9f95a23c
TL
161TEST_P(CompressorTest, round_trip_osdmap)
162{
163#include "osdmaps/osdmap.2982809.h"
164
165 auto compressor = Compressor::create(g_ceph_context, plugin);
166 bufferlist orig;
167 orig.append((char*)osdmap_a, sizeof(osdmap_a));
168 cout << "orig length " << orig.length() << std::endl;
169 uint32_t size = 128*1024;
170 OSDMap *o = new OSDMap;
171 o->decode(orig);
172 bufferlist fbl;
173 o->encode(fbl, o->get_encoding_features() | CEPH_FEATURE_RESERVED);
174 ASSERT_TRUE(fbl.contents_equal(orig));
175 for (int j = 0; j < 3; j++) {
176 bufferlist chunk;
177 uint32_t l = std::min(size, fbl.length() - j*size);
178 chunk.substr_of(fbl, j*size, l);
179 //fbl.rebuild();
180 bufferlist compressed;
181 int r = compressor->compress(chunk, compressed);
182 ASSERT_EQ(0, r);
183 bufferlist decompressed;
184 r = compressor->decompress(compressed, decompressed);
185 ASSERT_EQ(0, r);
186 ASSERT_EQ(decompressed.length(), chunk.length());
187 if (!decompressed.contents_equal(chunk)) {
188 cout << "FAILED, orig bl was\n" << fbl << std::endl;
189 ASSERT_TRUE(decompressed.contents_equal(chunk));
190 }
191 cout << "chunk " << chunk.length()
192 << " compressed " << compressed.length()
193 << " decompressed " << decompressed.length()
194 << " with " << plugin << std::endl;
195 }
196 delete o;
197}
198
7c673cae
FG
199TEST_P(CompressorTest, compress_decompress)
200{
201 const char* test = "This is test text";
202 int res;
203 int len = strlen(test);
204 bufferlist in, out;
205 bufferlist after;
206 bufferlist exp;
207 in.append(test, len);
208 res = compressor->compress(in, out);
209 EXPECT_EQ(res, 0);
210 res = compressor->decompress(out, after);
211 EXPECT_EQ(res, 0);
212 exp.append(test);
213 EXPECT_TRUE(exp.contents_equal(after));
214 after.clear();
215 size_t compressed_len = out.length();
216 out.append_zero(12);
11fdf7f2 217 auto it = out.cbegin();
7c673cae
FG
218 res = compressor->decompress(it, compressed_len, after);
219 EXPECT_EQ(res, 0);
220 EXPECT_TRUE(exp.contents_equal(after));
221
222 //large block and non-begin iterator for continuous block
223 std::string data;
224 data.resize(0x10000 * 1);
225 for(size_t i = 0; i < data.size(); i++)
226 data[i] = i / 256;
227 in.clear();
228 out.clear();
229 in.append(data);
230 exp = in;
231 res = compressor->compress(in, out);
232 EXPECT_EQ(res, 0);
233 compressed_len = out.length();
234 out.append_zero(0x10000 - out.length());
235 after.clear();
236 out.c_str();
237 bufferlist prefix;
238 prefix.append(string("some prefix"));
239 size_t prefix_len = prefix.length();
11fdf7f2
TL
240 prefix.claim_append(out);
241 out.swap(prefix);
242 it = out.cbegin();
9f95a23c 243 it += prefix_len;
7c673cae
FG
244 res = compressor->decompress(it, compressed_len, after);
245 EXPECT_EQ(res, 0);
246 EXPECT_TRUE(exp.contents_equal(after));
247}
248
249TEST_P(CompressorTest, sharded_input_decompress)
250{
251 const size_t small_prefix_size=3;
252
253 string test(128*1024,0);
254 int len = test.size();
255 bufferlist in, out;
256 in.append(test.c_str(), len);
257 int res = compressor->compress(in, out);
258 EXPECT_EQ(res, 0);
259 EXPECT_GT(out.length(), small_prefix_size);
260
261 bufferlist out2, tmp;
262 tmp.substr_of(out, 0, small_prefix_size );
263 out2.append( tmp );
264 size_t left = out.length()-small_prefix_size;
265 size_t offs = small_prefix_size;
266 while( left > 0 ){
11fdf7f2 267 size_t shard_size = std::min<size_t>(2048, left);
7c673cae
FG
268 tmp.substr_of(out, offs, shard_size );
269 out2.append( tmp );
270 left -= shard_size;
271 offs += shard_size;
272 }
273
274 bufferlist after;
275 res = compressor->decompress(out2, after);
276 EXPECT_EQ(res, 0);
277}
278
279void test_compress(CompressorRef compressor, size_t size)
280{
281 char* data = (char*) malloc(size);
282 for (size_t t = 0; t < size; t++) {
283 data[t] = (t & 0xff) | (t >> 8);
284 }
285 bufferlist in;
286 in.append(data, size);
c07f9fc5 287 for (size_t t = 0; t < 10000; t++) {
7c673cae
FG
288 bufferlist out;
289 int res = compressor->compress(in, out);
290 EXPECT_EQ(res, 0);
291 }
11fdf7f2 292 free(data);
7c673cae
FG
293}
294
295void test_decompress(CompressorRef compressor, size_t size)
296{
297 char* data = (char*) malloc(size);
298 for (size_t t = 0; t < size; t++) {
299 data[t] = (t & 0xff) | (t >> 8);
300 }
301 bufferlist in, out;
302 in.append(data, size);
303 int res = compressor->compress(in, out);
304 EXPECT_EQ(res, 0);
c07f9fc5 305 for (size_t t = 0; t < 10000; t++) {
7c673cae
FG
306 bufferlist out_dec;
307 int res = compressor->decompress(out, out_dec);
308 EXPECT_EQ(res, 0);
309 }
11fdf7f2 310 free(data);
7c673cae
FG
311}
312
313TEST_P(CompressorTest, compress_1024)
314{
315 test_compress(compressor, 1024);
316}
317
318TEST_P(CompressorTest, compress_2048)
319{
320 test_compress(compressor, 2048);
321}
322
323TEST_P(CompressorTest, compress_4096)
324{
325 test_compress(compressor, 4096);
326}
327
328TEST_P(CompressorTest, compress_8192)
329{
330 test_compress(compressor, 8192);
331}
332
333TEST_P(CompressorTest, compress_16384)
334{
335 test_compress(compressor, 16384);
336}
337
338TEST_P(CompressorTest, decompress_1024)
339{
340 test_decompress(compressor, 1024);
341}
342
343TEST_P(CompressorTest, decompress_2048)
344{
345 test_decompress(compressor, 2048);
346}
347
348TEST_P(CompressorTest, decompress_4096)
349{
350 test_decompress(compressor, 4096);
351}
352
353TEST_P(CompressorTest, decompress_8192)
354{
355 test_decompress(compressor, 8192);
356}
357
358TEST_P(CompressorTest, decompress_16384)
359{
360 test_decompress(compressor, 16384);
361}
362
363
9f95a23c 364INSTANTIATE_TEST_SUITE_P(
7c673cae
FG
365 Compressor,
366 CompressorTest,
367 ::testing::Values(
31f18b77
FG
368#ifdef HAVE_LZ4
369 "lz4",
370#endif
7c673cae
FG
371#ifdef __x86_64__
372 "zlib/isal",
373#endif
374 "zlib/noisal",
375 "snappy",
11fdf7f2
TL
376#ifdef HAVE_BROTLI
377 "brotli",
378#endif
7c673cae
FG
379 "zstd"));
380
381#ifdef __x86_64__
382
383TEST(ZlibCompressor, zlib_isal_compatibility)
384{
11fdf7f2
TL
385 g_conf().set_val("compressor_zlib_isal", "true");
386 g_ceph_context->_conf.apply_changes(nullptr);
7c673cae
FG
387 CompressorRef isal = Compressor::create(g_ceph_context, "zlib");
388 if (!isal) {
389 // skip the test if the plugin is not ready
390 return;
391 }
11fdf7f2
TL
392 g_conf().set_val("compressor_zlib_isal", "false");
393 g_ceph_context->_conf.apply_changes(nullptr);
7c673cae
FG
394 CompressorRef zlib = Compressor::create(g_ceph_context, "zlib");
395 char test[101];
396 srand(time(0));
397 for (int i=0; i<100; ++i)
398 test[i] = 'a' + rand()%26;
399 test[100] = '\0';
400 int len = strlen(test);
401 bufferlist in, out;
402 in.append(test, len);
403 // isal -> zlib
404 int res = isal->compress(in, out);
405 EXPECT_EQ(res, 0);
406 bufferlist after;
407 res = zlib->decompress(out, after);
408 EXPECT_EQ(res, 0);
409 bufferlist exp;
11fdf7f2 410 exp.append(static_cast<char*>(test));
7c673cae
FG
411 EXPECT_TRUE(exp.contents_equal(after));
412 after.clear();
413 out.clear();
414 exp.clear();
415 // zlib -> isal
416 res = zlib->compress(in, out);
417 EXPECT_EQ(res, 0);
418 res = isal->decompress(out, after);
419 EXPECT_EQ(res, 0);
11fdf7f2 420 exp.append(static_cast<char*>(test));
7c673cae
FG
421 EXPECT_TRUE(exp.contents_equal(after));
422}
423#endif
424
425TEST(CompressionPlugin, all)
426{
7c673cae
FG
427 CompressorRef compressor;
428 PluginRegistry *reg = g_ceph_context->get_plugin_registry();
429 EXPECT_TRUE(reg);
430 CompressionPlugin *factory = dynamic_cast<CompressionPlugin*>(reg->get_with_load("compressor", "invalid"));
431 EXPECT_FALSE(factory);
432 factory = dynamic_cast<CompressionPlugin*>(reg->get_with_load("compressor", "example"));
11fdf7f2 433 ASSERT_TRUE(factory);
7c673cae
FG
434 stringstream ss;
435 EXPECT_EQ(0, factory->factory(&compressor, &ss));
436 EXPECT_TRUE(compressor.get());
437 {
11fdf7f2 438 std::lock_guard l(reg->lock);
7c673cae
FG
439 EXPECT_EQ(-ENOENT, reg->remove("compressor", "does not exist"));
440 EXPECT_EQ(0, reg->remove("compressor", "example"));
441 EXPECT_EQ(0, reg->load("compressor", "example"));
442 }
443}
444
445#ifdef __x86_64__
446
447TEST(ZlibCompressor, isal_compress_zlib_decompress_random)
448{
11fdf7f2
TL
449 g_conf().set_val("compressor_zlib_isal", "true");
450 g_ceph_context->_conf.apply_changes(nullptr);
7c673cae
FG
451 CompressorRef isal = Compressor::create(g_ceph_context, "zlib");
452 if (!isal) {
453 // skip the test if the plugin is not ready
454 return;
455 }
11fdf7f2
TL
456 g_conf().set_val("compressor_zlib_isal", "false");
457 g_ceph_context->_conf.apply_changes(nullptr);
7c673cae
FG
458 CompressorRef zlib = Compressor::create(g_ceph_context, "zlib");
459
c07f9fc5 460 for (int cnt=0; cnt<100; cnt++)
7c673cae
FG
461 {
462 srand(cnt + 1000);
463 int log2 = (rand()%18) + 1;
464 int size = (rand() % (1 << log2)) + 1;
465
466 char test[size];
467 for (int i=0; i<size; ++i)
468 test[i] = rand()%256;
469 bufferlist in, out;
470 in.append(test, size);
471
472 int res = isal->compress(in, out);
473 EXPECT_EQ(res, 0);
474 bufferlist after;
475 res = zlib->decompress(out, after);
476 EXPECT_EQ(res, 0);
477 bufferlist exp;
478 exp.append(test, size);
479 EXPECT_TRUE(exp.contents_equal(after));
480 }
481}
482
483TEST(ZlibCompressor, isal_compress_zlib_decompress_walk)
484{
11fdf7f2
TL
485 g_conf().set_val("compressor_zlib_isal", "true");
486 g_ceph_context->_conf.apply_changes(nullptr);
7c673cae
FG
487 CompressorRef isal = Compressor::create(g_ceph_context, "zlib");
488 if (!isal) {
489 // skip the test if the plugin is not ready
490 return;
491 }
11fdf7f2
TL
492 g_conf().set_val("compressor_zlib_isal", "false");
493 g_ceph_context->_conf.apply_changes(nullptr);
7c673cae
FG
494 CompressorRef zlib = Compressor::create(g_ceph_context, "zlib");
495
c07f9fc5 496 for (int cnt=0; cnt<100; cnt++)
7c673cae
FG
497 {
498 srand(cnt + 1000);
499 int log2 = (rand()%18) + 1;
500 int size = (rand() % (1 << log2)) + 1;
501
502 int range = 1;
503
504 char test[size];
505 test[0] = rand()%256;
506 for (int i=1; i<size; ++i)
507 test[i] = test[i-1] + rand()%(range*2+1) - range;
508 bufferlist in, out;
509 in.append(test, size);
510
511 int res = isal->compress(in, out);
512 EXPECT_EQ(res, 0);
513 bufferlist after;
514 res = zlib->decompress(out, after);
515 EXPECT_EQ(res, 0);
516 bufferlist exp;
517 exp.append(test, size);
518 EXPECT_TRUE(exp.contents_equal(after));
519 }
520}
521
522#endif // __x86_64__
11fdf7f2
TL
523
524#ifdef HAVE_QATZIP
525TEST(QAT, enc_qat_dec_noqat) {
526#ifdef HAVE_LZ4
527 const char* alg_collection[] = {"zlib", "lz4", "snappy"};
528#else
529 const char* alg_collection[] = {"zlib", "snappy"};
530#endif
531 for (auto alg : alg_collection) {
532 g_conf().set_val("qat_compressor_enabled", "true");
533 CompressorRef q = Compressor::create(g_ceph_context, alg);
534 g_conf().set_val("qat_compressor_enabled", "false");
535 CompressorRef noq = Compressor::create(g_ceph_context, alg);
536
537 // generate random buffer
538 for (int cnt=0; cnt<100; cnt++) {
539 srand(cnt + 1000);
540 int log2 = (rand()%18) + 1;
541 int size = (rand() % (1 << log2)) + 1;
542
543 char test[size];
544 for (int i=0; i<size; ++i)
545 test[i] = rand()%256;
546 bufferlist in, out;
547 in.append(test, size);
548
549 int res = q->compress(in, out);
550 EXPECT_EQ(res, 0);
551 bufferlist after;
552 res = noq->decompress(out, after);
553 EXPECT_EQ(res, 0);
554 bufferlist exp;
555 exp.append(test, size);
556 EXPECT_TRUE(exp.contents_equal(after));
557 }
558 }
559}
560
561TEST(QAT, enc_noqat_dec_qat) {
562#ifdef HAVE_LZ4
563 const char* alg_collection[] = {"zlib", "lz4", "snappy"};
564#else
565 const char* alg_collection[] = {"zlib", "snappy"};
566#endif
567 for (auto alg : alg_collection) {
568 g_conf().set_val("qat_compressor_enabled", "true");
569 CompressorRef q = Compressor::create(g_ceph_context, alg);
570 g_conf().set_val("qat_compressor_enabled", "false");
571 CompressorRef noq = Compressor::create(g_ceph_context, alg);
572
573 // generate random buffer
574 for (int cnt=0; cnt<100; cnt++) {
575 srand(cnt + 1000);
576 int log2 = (rand()%18) + 1;
577 int size = (rand() % (1 << log2)) + 1;
578
579 char test[size];
580 for (int i=0; i<size; ++i)
581 test[i] = rand()%256;
582 bufferlist in, out;
583 in.append(test, size);
584
585 int res = noq->compress(in, out);
586 EXPECT_EQ(res, 0);
587 bufferlist after;
588 res = q->decompress(out, after);
589 EXPECT_EQ(res, 0);
590 bufferlist exp;
591 exp.append(test, size);
592 EXPECT_TRUE(exp.contents_equal(after));
593 }
594 }
595}
596
597#endif // HAVE_QATZIP