Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions conan.lock
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
"gflags/2.2.2",
"glog/0.7.1",
"gtest/1.17.0",
"libbacktrace/cci.20240730",
"libbacktrace/cci.20210118",
"libfuse/3.16.2",
"libunwind/1.8.1",
"liburing/2.11",
Expand Down Expand Up @@ -49,7 +49,7 @@
"libunwind/1.8.1"
],
"libbacktrace/[>=cci.20210118]": [
"libbacktrace/cci.20240730"
"libbacktrace/cci.20210118"
],
"openssl/[>=3 <4]": [
"openssl/[>=3.6.0 <4]"
Expand All @@ -65,7 +65,7 @@
"zlib/[>=1.3.1 <2]"
],
"libbacktrace/cci.20210118": [
"libbacktrace/[>=cci.20240730]"
"libbacktrace/[>=cci.20210118]"
],
"libunwind/1.8.0": [
"libunwind/[>=1.8.1 <2]"
Expand Down
2 changes: 1 addition & 1 deletion conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ def requirements(self):
self.requires("boost/[>=1.88.0 <2]", **VISIBLE)
self.requires("cli11/[>=2.5.0 <3]", **VISIBLE)
self.requires("glog/[>=0.7.1 <1]", **VISIBLE)
self.requires("libbacktrace/[>=cci.20240730]", **VISIBLE)
self.requires("libbacktrace/[>=cci.20210118]", **VISIBLE)
self.requires("openssl/[>=3.6.0 <4]", **VISIBLE)
self.requires("xxhash/[>=0.8.3 <1]", **VISIBLE)
self.requires("zlib/[>=1.3.1 <2]")
Expand Down
30 changes: 22 additions & 8 deletions src/llfs/bloom_filter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
//
#include <llfs/conversion.hpp>

#include <batteries/env.hpp>

namespace llfs {

//==#==========+==+=+=++=+++++++++++-+-+--+----- --- -- - - - -
Expand Down Expand Up @@ -307,19 +309,26 @@ std::ostream& operator<<(std::ostream& out, const BloomFilterConfig& t)

//==#==========+==+=+=++=+++++++++++-+-+--+----- --- -- - - - -
//
void PackedBloomFilter::initialize(const BloomFilterConfig& config) noexcept
bool avx512_enabled() noexcept
{
[[maybe_unused]] static const bool init = [] {
LLFS_LOG_INFO() <<
static const bool enabled = [] {
bool value = false;
#ifdef __AVX512F__
"AVX512 enabled"
#else
"AVX512 NOT enabled"
value = batt::getenv_as<bool>("LLFS_AVX512").value_or(true);
#endif
;
return true;
LLFS_LOG_INFO() << "AVX512 " << (value ? "enabled" : "NOT enabled");
return value;
}();

return enabled;
}

//==#==========+==+=+=++=+++++++++++-+-+--+----- --- -- - - - -
//
void PackedBloomFilter::initialize(const BloomFilterConfig& config) noexcept
{
[[maybe_unused]] static const bool init = avx512_enabled();

BATT_CHECK_NE(config.word_count(), 0);
BATT_CHECK_NE(config.block_count(), 0);

Expand All @@ -332,6 +341,11 @@ void PackedBloomFilter::initialize(const BloomFilterConfig& config) noexcept
this->block_count_pre_mul_shift_ = batt::log2_ceil(this->block_count_) + 1;
this->block_count_post_mul_shift_ = 64 - this->block_count_pre_mul_shift_;

const std::uintptr_t addr_int = reinterpret_cast<std::uintptr_t>((const void*)this->words);
BATT_CHECK_EQ(addr_int % (512 / 8), 0)
<< BATT_INSPECT(addr_int) << BATT_INSPECT((const void*)this)
<< BATT_INSPECT((const void*)this->words);

this->check_invariants();
}

Expand Down
88 changes: 52 additions & 36 deletions src/llfs/bloom_filter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@

namespace llfs {

bool avx512_enabled() noexcept;

/** \brief Physical layout of a Bloom filter; each carries different trade-offs.
*/
enum struct BloomFilterLayout : u8 {
Expand Down Expand Up @@ -185,7 +187,7 @@ std::ostream& operator<<(std::ostream& out, const BloomFilterConfig& t);
template <typename T>
struct BloomFilterQuery {
T key;
batt::SmallVec<u64, 24> hash;
batt::SmallVec<u64, 36> hash;
batt::SmallVec<u64, 8> mask;
u32 mask_n_hashes = 0;

Expand Down Expand Up @@ -282,6 +284,7 @@ struct BloomFilterQuery {

// The mask should exactly as large as the block; all 0's initially.
//
this->mask.clear();
this->mask.resize(kBlockWord64Size, 0);

// Each time through the loop, we pull enough bits from this->hash[1..] to locate a single bit
Expand Down Expand Up @@ -318,6 +321,7 @@ struct BloomFilterQuery {
shift = 0;
++src_val_j;
}
BATT_ASSERT_LT(shift, kShiftOverflow);
}

// Finally store the new number of hashes.
Expand Down Expand Up @@ -400,7 +404,7 @@ struct PackedBloomFilter {
//
little_u8 block_count_post_mul_shift_;

// Align to 64-bit boundary.
// Align to 512-bit boundary.
//
little_u8 reserved_[41];

Expand Down Expand Up @@ -532,6 +536,8 @@ struct PackedBloomFilter {

const usize block_i = this->block_index_from_hash(query.hash[0]);

BATT_ASSERT_LT(block_i, this->block_count_.value());

return (this->words[block_i] & query.mask[0]) == query.mask[0];
}

Expand All @@ -545,36 +551,41 @@ struct PackedBloomFilter {
const usize block_i = this->block_index_from_hash(query.hash[0]);
const usize block_first_word_i = block_i * 8;

BATT_ASSERT_LT(block_i, this->block_count_.value());
BATT_ASSERT_LT(block_first_word_i + 7, this->word_count_.value());

const i64* const block_p = (const i64*)&this->words[block_first_word_i];
const i64* const query_p = (const i64*)&query.mask[0];

BATT_CHECK_EQ(query.mask.size(), 8);

if (avx512_enabled()) {
#ifdef __AVX512F__

__m512i block_512 = {block_p[0], block_p[1], block_p[2], block_p[3],
block_p[4], block_p[5], block_p[6], block_p[7]};
__m512i block_512 = {block_p[0], block_p[1], block_p[2], block_p[3],
block_p[4], block_p[5], block_p[6], block_p[7]};

__m512i query_512 = {query_p[0], query_p[1], query_p[2], query_p[3],
query_p[4], query_p[5], query_p[6], query_p[7]};
__m512i query_512 = {query_p[0], query_p[1], query_p[2], query_p[3],
query_p[4], query_p[5], query_p[6], query_p[7]};

const bool match = _mm512_cmp_epi64_mask(_mm512_and_epi64(block_512, query_512), query_512,
_MM_CMPINT_EQ) == __mmask8{0b11111111};
const bool match = _mm512_cmp_epi64_mask(_mm512_and_epi64(block_512, query_512), query_512,
_MM_CMPINT_EQ) == __mmask8{0b11111111};

return match;
return match;

#else

return ((block_p[0] & query_p[0]) == query_p[0]) && //
((block_p[1] & query_p[1]) == query_p[1]) && //;
((block_p[2] & query_p[2]) == query_p[2]) && //;
((block_p[3] & query_p[3]) == query_p[3]) && //;
((block_p[4] & query_p[4]) == query_p[4]) && //;
((block_p[5] & query_p[5]) == query_p[5]) && //;
((block_p[6] & query_p[6]) == query_p[6]) && //;
((block_p[7] & query_p[7]) == query_p[7]);

BATT_PANIC() << "AVX512 not compiled in!";
#endif
} else {
return ((block_p[0] & query_p[0]) == query_p[0]) && //
((block_p[1] & query_p[1]) == query_p[1]) && //;
((block_p[2] & query_p[2]) == query_p[2]) && //;
((block_p[3] & query_p[3]) == query_p[3]) && //;
((block_p[4] & query_p[4]) == query_p[4]) && //;
((block_p[5] & query_p[5]) == query_p[5]) && //;
((block_p[6] & query_p[6]) == query_p[6]) && //;
((block_p[7] & query_p[7]) == query_p[7]);
}
}

template <typename T>
Expand All @@ -583,34 +594,39 @@ struct PackedBloomFilter {
const usize block_i = this->block_index_from_hash(query.hash[0]);
const usize block_first_word_i = block_i * 8;

BATT_ASSERT_LT(block_i, this->block_count_.value());
BATT_ASSERT_LT(block_first_word_i + 7, this->word_count_.value());

const i64* const block_p = (const i64*)&this->words[block_first_word_i];
const i64* const query_p = (const i64*)query.mask.data();

if (avx512_enabled()) {
#ifdef __AVX512F__

__m512i block_512 = {block_p[0], block_p[1], block_p[2], block_p[3],
block_p[4], block_p[5], block_p[6], block_p[7]};
__m512i block_512 = {block_p[0], block_p[1], block_p[2], block_p[3],
block_p[4], block_p[5], block_p[6], block_p[7]};

__m512i query_512 = {query_p[0], query_p[1], query_p[2], query_p[3],
query_p[4], query_p[5], query_p[6], query_p[7]};
__m512i query_512 = {query_p[0], query_p[1], query_p[2], query_p[3],
query_p[4], query_p[5], query_p[6], query_p[7]};

const bool match = _mm512_cmp_epi64_mask(_mm512_and_epi64(block_512, query_512), query_512,
_MM_CMPINT_EQ) == __mmask8{0b11111111};
const bool match = _mm512_cmp_epi64_mask(_mm512_and_epi64(block_512, query_512), query_512,
_MM_CMPINT_EQ) == __mmask8{0b11111111};

return match;
return match;

#else

return ((block_p[0] & query_p[0]) == query_p[0]) && //
((block_p[1] & query_p[1]) == query_p[1]) && //;
((block_p[2] & query_p[2]) == query_p[2]) && //;
((block_p[3] & query_p[3]) == query_p[3]) && //;
((block_p[4] & query_p[4]) == query_p[4]) && //;
((block_p[5] & query_p[5]) == query_p[5]) && //;
((block_p[6] & query_p[6]) == query_p[6]) && //;
((block_p[7] & query_p[7]) == query_p[7]);

BATT_PANIC() << "AVX512 not compiled in!";
#endif
} else {
return ((block_p[0] & query_p[0]) == query_p[0]) && //
((block_p[1] & query_p[1]) == query_p[1]) && //;
((block_p[2] & query_p[2]) == query_p[2]) && //;
((block_p[3] & query_p[3]) == query_p[3]) && //;
((block_p[4] & query_p[4]) == query_p[4]) && //;
((block_p[5] & query_p[5]) == query_p[5]) && //;
((block_p[6] & query_p[6]) == query_p[6]) && //;
((block_p[7] & query_p[7]) == query_p[7]);
}
}

template <typename T>
Expand Down
11 changes: 11 additions & 0 deletions src/llfs/packed_bloom_filter_page.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,11 +68,19 @@ struct PackedBloomFilterPage {
*/
little_u64 bit_count;

/** \brief The number of keys in this filter.
*/
little_u64 key_count;

/** \brief If this filter is associated with another page, the page id of that page is stored
* here.
*/
PackedPageId src_page_id;

// Needed to make sure bloom_filter's word array starts on a 512-bit boundary.
//
u8 pad_[24];

/** \brief The Bloom filter header; the actual filter bits follow this struct, and may extend to
* the end of the page.
*/
Expand Down Expand Up @@ -102,6 +110,8 @@ struct PackedBloomFilterPage {
void check_integrity() const;
};

static_assert(sizeof(PackedBloomFilterPage) == 128);

//==#==========+==+=+=++=+++++++++++-+-+--+----- --- -- - - - -
//
/** \brief Builds a PackedBloomFilterPage in the passed page buffer from the items in the passed
Expand Down Expand Up @@ -155,6 +165,7 @@ StatusOr<const PackedBloomFilterPage*> build_bloom_filter_page(
// Grab the item count to figure out how to size the filter.
//
const u64 item_count = std::distance(std::begin(items), std::end(items));
packed_filter_page->key_count = item_count;

// Calculate the total filter bits to use.
//
Expand Down