Skip to content

Commit 80e4012

Browse files
authored
chore: Add benchmarks of qlist compression paths (#4543)
1. Add testdata, move the existing test data to zstd-compressed format. 2. Add benchmarks in qlist_test that add lots of records, forcing compression of inner noded, or read compressed list checking the decompression. Currently qlist uses valkey compression algorithm. On my machine: 1. (valkey) Compression is 5 times slower than no compression. 2. Decompression is 37 times slower. Signed-off-by: Roman Gershman <[email protected]>
1 parent bff9cf6 commit 80e4012

File tree

9 files changed

+79
-760
lines changed

9 files changed

+79
-760
lines changed

.clangd

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
Diagnostics:
2+
UnusedIncludes: None
3+
MissingIncludes: None
4+
Includes:
5+
IgnoreHeader: base/*.h
6+
7+
CompileFlags:
8+
CompilationDatabase: build-dbg/ # Search for compile_commands.json

src/core/CMakeLists.txt

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ cxx_link(dash_bench dfly_core redis_test_lib)
1818
cxx_test(dfly_core_test dfly_core TRDP::fast_float LABELS DFLY)
1919
cxx_test(compact_object_test dfly_core LABELS DFLY)
2020
cxx_test(extent_tree_test dfly_core LABELS DFLY)
21-
cxx_test(dash_test dfly_core file redis_test_lib DATA testdata/ids.txt LABELS DFLY)
21+
cxx_test(dash_test dfly_core file redis_test_lib DATA testdata/ids.txt.zst LABELS DFLY)
2222
cxx_test(interpreter_test dfly_core LABELS DFLY)
2323

2424
cxx_test(string_set_test dfly_core LABELS DFLY)
@@ -29,4 +29,4 @@ cxx_test(score_map_test dfly_core LABELS DFLY)
2929
cxx_test(flatbuffers_test dfly_core TRDP::flatbuffers LABELS DFLY)
3030
cxx_test(bloom_test dfly_core LABELS DFLY)
3131
cxx_test(allocation_tracker_test dfly_core absl::random_random LABELS DFLY)
32-
cxx_test(qlist_test dfly_core LABELS DFLY)
32+
cxx_test(qlist_test dfly_core DATA testdata/list.txt.zst LABELS DFLY)

src/core/dash_test.cc

+4-5
Original file line numberDiff line numberDiff line change
@@ -882,12 +882,11 @@ struct BlankPolicy : public BasicDashPolicy {
882882
// into a new segment, not every item finds a place.
883883
TEST_F(DashTest, SplitBug) {
884884
DashTable<uint64_t, uint64_t, BlankPolicy> table;
885+
string path = base::ProgramRunfile("testdata/ids.txt.zst");
886+
io::Result<io::Source*> src = io::OpenUncompressed(path);
887+
ASSERT_TRUE(src) << src.error();
885888

886-
io::ReadonlyFileOrError fl_err =
887-
io::OpenRead(base::ProgramRunfile("testdata/ids.txt"), io::ReadonlyFile::Options{});
888-
CHECK(fl_err);
889-
io::FileSource fs(std::move(*fl_err));
890-
io::LineReader lr(&fs, DO_NOT_TAKE_OWNERSHIP);
889+
io::LineReader lr(*src, TAKE_OWNERSHIP);
891890
string_view line;
892891
uint64_t val;
893892
while (lr.Next(&line)) {

src/core/qlist.cc

+4-1
Original file line numberDiff line numberDiff line change
@@ -206,9 +206,12 @@ bool CompressNode(QList::Node* node) {
206206
if (((lzf->sz = lzf_compress(node->entry, node->sz, lzf->compressed, node->sz, sdata)) == 0) ||
207207
lzf->sz + MIN_COMPRESS_IMPROVE >= node->sz) {
208208
/* lzf_compress aborts/rejects compression if value not compressible. */
209+
DVLOG(2) << "Uncompressable " << node->sz << " vs " << lzf->sz;
209210
zfree(lzf);
211+
210212
return false;
211213
}
214+
DVLOG(2) << "Compressed " << node->sz << " to " << lzf->sz;
212215

213216
lzf = (quicklistLZF*)zrealloc(lzf, sizeof(*lzf) + lzf->sz);
214217
zfree(node->entry);
@@ -352,7 +355,7 @@ void QList::Clear() {
352355
}
353356

354357
void QList::Push(string_view value, Where where) {
355-
DVLOG(2) << "Push " << absl::CHexEscape(value) << " " << (where == HEAD ? "HEAD" : "TAIL");
358+
DVLOG(3) << "Push " << absl::CHexEscape(value) << " " << (where == HEAD ? "HEAD" : "TAIL");
356359

357360
/* The head and tail should never be compressed (we don't attempt to decompress them) */
358361
if (head_) {

src/core/qlist_test.cc

+60-5
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
#include "base/gtest.h"
1313
#include "base/logging.h"
1414
#include "core/mi_memory_resource.h"
15+
#include "io/file.h"
16+
#include "io/line_reader.h"
1517

1618
extern "C" {
1719
#include "redis/listpack.h"
@@ -24,7 +26,7 @@ using namespace std;
2426
using namespace testing;
2527
using absl::StrCat;
2628

27-
static int _ql_verify_compress(const QList& ql) {
29+
static int ql_verify_compress(const QList& ql) {
2830
int errors = 0;
2931
unsigned compress_param = ql.compress_param();
3032
if (compress_param > 0) {
@@ -115,19 +117,23 @@ static int ql_verify(const QList& ql, uint32_t nc, uint32_t count, uint32_t head
115117
errors++;
116118
}
117119

118-
errors += _ql_verify_compress(ql);
120+
errors += ql_verify_compress(ql);
119121
return errors;
120122
}
121123

124+
static void SetupMalloc() {
125+
// configure redis lib zmalloc which requires mimalloc heap to work.
126+
auto* tlh = mi_heap_get_backing();
127+
init_zmalloc_threadlocal(tlh);
128+
}
129+
122130
class QListTest : public ::testing::Test {
123131
protected:
124132
QListTest() : mr_(mi_heap_get_backing()) {
125133
}
126134

127135
static void SetUpTestSuite() {
128-
// configure redis lib zmalloc which requires mimalloc heap to work.
129-
auto* tlh = mi_heap_get_backing();
130-
init_zmalloc_threadlocal(tlh);
136+
SetupMalloc();
131137
}
132138

133139
static void TearDownTestSuite() {
@@ -848,4 +854,53 @@ TEST_P(OptionsTest, IndexFrom500) {
848854
ASSERT_FALSE(it.Next());
849855
}
850856

857+
static void BM_QListCompress(benchmark::State& state) {
858+
SetupMalloc();
859+
860+
string path = base::ProgramRunfile("testdata/list.txt.zst");
861+
io::Result<io::Source*> src = io::OpenUncompressed(path);
862+
CHECK(src) << src.error();
863+
io::LineReader lr(*src, TAKE_OWNERSHIP);
864+
string_view line;
865+
vector<string> lines;
866+
while (lr.Next(&line)) {
867+
lines.push_back(string(line));
868+
}
869+
870+
while (state.KeepRunning()) {
871+
QList ql(-2, state.range(0)); // uses differrent compression modes, see below.
872+
for (const string& l : lines) {
873+
ql.Push(l, QList::TAIL);
874+
}
875+
DVLOG(1) << ql.node_count() << ", " << ql.MallocUsed(true);
876+
}
877+
}
878+
BENCHMARK(BM_QListCompress)
879+
->Arg(0) // no compression
880+
->Arg(1) // compress all nodes but edges.
881+
->Arg(4); // compress all nodes but 4 nodes from edges.
882+
883+
static void BM_QListUncompress(benchmark::State& state) {
884+
SetupMalloc();
885+
886+
string path = base::ProgramRunfile("testdata/list.txt.zst");
887+
io::Result<io::Source*> src = io::OpenUncompressed(path);
888+
CHECK(src) << src.error();
889+
io::LineReader lr(*src, TAKE_OWNERSHIP);
890+
string_view line;
891+
QList ql(-2, state.range(0));
892+
893+
while (lr.Next(&line)) {
894+
ql.Push(line, QList::TAIL);
895+
}
896+
897+
LOG(INFO) << "MallocUsed " << ql.compress_param() << ": " << ql.MallocUsed(true) << ", "
898+
<< ql.MallocUsed(false);
899+
900+
while (state.KeepRunning()) {
901+
ql.Iterate([](const QList::Entry& e) { return true; }, 0, -1);
902+
}
903+
}
904+
BENCHMARK(BM_QListUncompress)->Arg(0)->Arg(1)->Arg(4);
905+
851906
} // namespace dfly

0 commit comments

Comments
 (0)