Skip to content

Commit 9db3b57

Browse files
committed
Add Morton filters
1 parent 061bf98 commit 9db3b57

File tree

4 files changed

+334
-1
lines changed

4 files changed

+334
-1
lines changed

benchmarks/bulk-insert-and-query.cc

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
#include <set>
2020
#include <stdio.h>
2121

22+
// morton
23+
#include "compressed_cuckoo_filter.h"
24+
#include "morton_sample_configs.h"
25+
2226
#include "cuckoofilter.h"
2327
#include "cuckoofilter_stable.h"
2428
#include "xorfilter.h"
@@ -53,6 +57,7 @@ using namespace xorfilter_plus;
5357
using namespace bloomfilter;
5458
using namespace counting_bloomfilter;
5559
using namespace gcsfilter;
60+
using namespace CompressedCuckoo; // Morton filter namespace
5661
#ifdef __AVX2__
5762
using namespace gqfilter;
5863
#endif
@@ -308,6 +313,52 @@ struct FilterAPI<XorFilter<ItemType, FingerprintType>> {
308313
}
309314
};
310315

316+
class MortonFilter {
317+
Morton3_8* filter;
318+
size_t size;
319+
public:
320+
MortonFilter(const size_t size) {
321+
filter = new Morton3_8((size_t) (2.1 * size) + 64);
322+
this->size = size;
323+
}
324+
~MortonFilter() {
325+
delete filter;
326+
}
327+
void Add(uint64_t key) {
328+
filter->insert(key);
329+
}
330+
bool Contain(uint64_t &item) {
331+
return filter->likely_contains(item);
332+
};
333+
size_t SizeInBytes() const {
334+
// TODO don't know how to get / calculate it
335+
return size;
336+
}
337+
};
338+
339+
template<>
340+
struct FilterAPI<MortonFilter> {
341+
using Table = MortonFilter;
342+
static Table ConstructFromAddCount(size_t add_count) {
343+
return Table(add_count);
344+
}
345+
static void Add(uint64_t key, Table* table) {
346+
table->Add(key);
347+
}
348+
static void AddAll(const vector<uint64_t> keys, const size_t start, const size_t end, Table* table) {
349+
for(int i=start; i<end; i++) {
350+
table->Add(keys[i]);
351+
}
352+
}
353+
static void Remove(uint64_t key, Table * table) {
354+
throw std::runtime_error("Unsupported");
355+
}
356+
CONTAIN_ATTRIBUTES static bool Contain(uint64_t key, Table * table) {
357+
return table->Contain(key);
358+
}
359+
};
360+
361+
311362
class XorSingle {
312363
xor8_s filter;
313364
public:
@@ -317,7 +368,7 @@ class XorSingle {
317368
}
318369
}
319370
~XorSingle() {
320-
::xor8_free(&filter);
371+
xor8_free(&filter);
321372
}
322373
bool AddAll(const uint64_t* data, const size_t start, const size_t end) {
323374
return xor8_buffered_populate(data + start, end - start, &filter);
@@ -887,6 +938,7 @@ int main(int argc, char * argv[]) {
887938
{62, "SuccCountBlockBloom10"},
888939

889940
{70, "Xor8-singleheader"},
941+
{80, "Morton"},
890942

891943
// Sort
892944
{100, "Sort"},
@@ -1345,6 +1397,14 @@ int main(int argc, char * argv[]) {
13451397
cout << setw(NAME_WIDTH) << names[a] << cf << endl;
13461398
}
13471399

1400+
a = 80;
1401+
if (algorithmId == a || algorithmId < 0 || (algos.find(a) != algos.end())) {
1402+
auto cf = FilterBenchmark<
1403+
MortonFilter>(
1404+
add_count, to_add, distinct_add, to_lookup, distinct_lookup, intersectionsize, hasduplicates, mixed_sets, seed, true);
1405+
cout << setw(NAME_WIDTH) << names[a] << cf << endl;
1406+
}
1407+
13481408
// Sort ----------------------------------------------------------
13491409
a = 100;
13501410
if (algorithmId == a || algorithmId < 0 || (algos.find(a) != algos.end())) {
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
Copyright (c) 2019 Advanced Micro Devices, Inc.
3+
4+
Permission is hereby granted, free of charge, to any person obtaining a copy
5+
of this software and associated documentation files (the "Software"), to deal
6+
in the Software without restriction, including without limitation the rights
7+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
copies of the Software, and to permit persons to whom the Software is
9+
furnished to do so, subject to the following conditions:
10+
11+
The above copyright notice and this permission notice shall be included in
12+
all copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+
THE SOFTWARE.
21+
22+
Author: Alex D. Breslow
23+
Advanced Micro Devices, Inc.
24+
AMD Research
25+
*/
26+
#ifndef _COMPRESSED_CUCKOO_CONFIG_H
27+
#define _COMPRESSED_CUCKOO_CONFIG_H
28+
29+
namespace CompressedCuckoo{
30+
// See vector_types.h for more types and for tuning the vector width and
31+
// atom types
32+
const bool g_cache_aligned_allocate = true;
33+
const size_t g_cache_line_size_bytes = 64; // Change this as necessary
34+
const uint64_t stash_prefix_tag_len = 4;
35+
36+
// Allows for up to 255 items per block
37+
const uint8_t max_fullness_counter_width = 8;
38+
constexpr atom_t one = static_cast<atom_t>(1);
39+
40+
enum struct AlternateBucketSelectionMethodEnum{
41+
TABLE_BASED_OFFSET,
42+
FUNCTION_BASED_OFFSET,
43+
FAN_ET_AL_PARTIAL_KEY // Only use this if you can guarantee the total buckets
44+
// in the filter is a power of two
45+
};
46+
47+
enum struct InsertionMethodEnum{
48+
FIRST_FIT,
49+
TWO_CHOICE,
50+
HYBRID_SIMPLE,
51+
HYBRID_PIECEWISE, // Starts off as first-fit and then transitions to two choice
52+
// once you hit a certain load factor
53+
FIRST_FIT_OPT, // Transitions between two implementations of first-fit
54+
};
55+
56+
enum struct CounterReadMethodEnum{
57+
READ_SIMPLE,
58+
READ_CROSS,
59+
READ_RAW, // If counters are always in atom 0 of block 0, just read that.
60+
// NOTE: This is prone to bugs, if you rearrange the storage of
61+
// of the counters within a block, so beware.
62+
READ_RAW128 // Read the first 128 bits from the block. See comment above.
63+
};
64+
65+
enum struct FingerprintReadMethodEnum{
66+
READ_SIMPLE,
67+
READ_CROSS,
68+
READ_BYTE // Special optimization for 8-bit fingerprints that are byte
69+
// aligned
70+
// RAW reads don't make sense here. We don't statically know which atom
71+
// that needs to be read. It may make sense with 128-bit atoms, but
72+
// my benchmarking showed 64-bit atoms to be faster.
73+
};
74+
75+
enum struct FingerprintComparisonMethodEnum{
76+
VARIABLE_COUNT,
77+
FIXED_COUNT_AGGRESSIVE,
78+
SEMI_FIXED
79+
};
80+
81+
enum struct ReductionMethodEnum{
82+
POP_CNT, // Must only use when counters fit into a single atom
83+
PARALLEL_REDUCE,
84+
NAIVE_FULL_EXCLUSIVE_SCAN,
85+
};
86+
87+
enum struct OverflowTrackingArrayHashingMethodEnum{
88+
// Daniel Lemire's fast hashing method
89+
LEMIRE_FINGERPRINT_MULTIPLY,
90+
RAW_BUCKET_HASH,
91+
CLUSTERED_BUCKET_HASH,
92+
};
93+
94+
enum struct InsertStatus{
95+
FAILED_TO_INSERT = 0,
96+
PLACED_IN_PRIMARY_BUCKET = 1,
97+
PLACED_IN_SECONDARY_BUCKET = 2
98+
};
99+
100+
101+
} // End of CompressedCuckoo namespace
102+
103+
#endif

src/morton/test_util.h

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
Copyright (c) 2019 Advanced Micro Devices, Inc.
3+
4+
Permission is hereby granted, free of charge, to any person obtaining a copy
5+
of this software and associated documentation files (the "Software"), to deal
6+
in the Software without restriction, including without limitation the rights
7+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
copies of the Software, and to permit persons to whom the Software is
9+
furnished to do so, subject to the following conditions:
10+
11+
The above copyright notice and this permission notice shall be included in
12+
all copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+
THE SOFTWARE.
21+
22+
Author: Alex D. Breslow
23+
Advanced Micro Devices, Inc.
24+
AMD Research
25+
*/
26+
#ifndef _TEST_UTIL_H
27+
#define _TEST_UTIL_H
28+
29+
namespace Test{
30+
std::string pass(bool success_status){
31+
return std::string(success_status ? "SUCCESS" : "FAILURE");
32+
}
33+
};
34+
35+
#endif

src/morton/util.h

Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
/*
2+
Copyright (c) 2019 Advanced Micro Devices, Inc.
3+
4+
Permission is hereby granted, free of charge, to any person obtaining a copy
5+
of this software and associated documentation files (the "Software"), to deal
6+
in the Software without restriction, including without limitation the rights
7+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
copies of the Software, and to permit persons to whom the Software is
9+
furnished to do so, subject to the following conditions:
10+
11+
The above copyright notice and this permission notice shall be included in
12+
all copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20+
THE SOFTWARE.
21+
22+
Author: Alex D. Breslow
23+
Advanced Micro Devices, Inc.
24+
AMD Research
25+
*/
26+
#ifndef _UTIL_H
27+
#define _UTIL_H
28+
29+
#include <cstdint>
30+
#include <string>
31+
#include <sstream>
32+
#include <cmath>
33+
34+
#include <iostream>
35+
36+
#include "vector_types.h"
37+
38+
// FIXME: Put guards around this
39+
// For BMI2 pdep instruction
40+
#ifdef __BMI2__
41+
#include "x86intrin.h"
42+
#endif
43+
44+
namespace util{
45+
46+
template<class INT_TYPE>
47+
inline std::string bin_string(INT_TYPE integer, uint32_t spacing){
48+
std::stringstream ss;
49+
for(int32_t i = sizeof(integer) * 8 - 1; i > -1; i--){
50+
ss << ((integer >> i) & 1 ? '1' : '0');
51+
if(i % spacing == 0){
52+
ss << ' ';
53+
}
54+
}
55+
return ss.str();
56+
}
57+
58+
template<class INT_TYPE>
59+
inline std::string bin_string(INT_TYPE integer){
60+
return bin_string<INT_TYPE>(integer, 8 * sizeof(INT_TYPE));
61+
}
62+
63+
// This could be implemented using fancy binary arithmatic or builtins,
64+
// but this probably suffices if the integer is known at compile time.
65+
constexpr inline uint32_t log2ceil(uint32_t integer){
66+
//return ceil(log2(integer));
67+
return 32u - __builtin_clz(integer - 1u);
68+
}
69+
70+
// See https://lemire.me/blog/2016/06/27
71+
// These functions implement a fast alternative to the modulo reduction.
72+
// The algorithm is presented by Professor Daniel Lemire of the University
73+
// of Quebec in his outstanding blog, which is under a Creative Commons
74+
// Attribution-ShareAlike 3.0 Unported License.
75+
// See https://creativecommons.org/licenses/by-sa/3.0/us/ and
76+
// https://lemire.me/blog/terms-of-use/.
77+
template<typename T>
78+
inline T fast_mod_alternative(T raw_hash, T modulus, T hash_width_in_bits);
79+
80+
template<>
81+
inline uint64_t fast_mod_alternative<uint64_t>(uint64_t raw_hash,
82+
uint64_t modulus, uint64_t hash_width_in_bits){
83+
return (static_cast<__uint128_t>(raw_hash) * modulus) >> hash_width_in_bits;
84+
}
85+
86+
template<>
87+
inline uint32_t fast_mod_alternative<uint32_t>(uint32_t raw_hash,
88+
uint32_t modulus, uint32_t hash_width_in_bits){
89+
return (static_cast<__uint64_t>(raw_hash) * modulus) >> hash_width_in_bits;
90+
}
91+
92+
template<class TN, class T>
93+
inline TN fast_mod_alternativeN(TN raw_hashes, T modulus);
94+
95+
template<class ARRAY_TYPE>
96+
inline void print_array(const std::string& name, const ARRAY_TYPE& array){
97+
std::cout << name << " [ ";
98+
for(uint32_t i = 0; i < batch_size; i++){
99+
std::cout << static_cast<uint32_t>(array[i]) << " ";
100+
}
101+
std::cout << "]\n";
102+
}
103+
104+
template<>
105+
inline vN_u32 fast_mod_alternativeN<vN_u32, uint32_t>(vN_u32 raw_hashes, uint32_t modulus){
106+
for(uint32_t i = 0; i < _N; i++){
107+
static_assert(_N <= 8, "Vector width exceeds AVX/AVX2's 256-bit vector width\n");
108+
raw_hashes[i] = static_cast<uint32_t>((static_cast<__uint64_t>(raw_hashes[i]) * modulus) >> 32U);
109+
}
110+
return raw_hashes;
111+
}
112+
113+
} // End of util namespace
114+
115+
116+
// FIXME: Not yet tested
117+
std::ostream& operator<<(std::ostream& os, __uint128_t integer){
118+
std::stringstream ss;
119+
__uint128_t sqrt_power10 = static_cast<__uint128_t>(10000000000000000000ull);
120+
// log10 of 2^127 is between 38 and 39, so start with 38 zeros
121+
__int128_t power10 = sqrt_power10 * sqrt_power10;
122+
while(static_cast<__uint128_t>(0) / power10 == 0){
123+
power10 /= 10;
124+
}
125+
while(power10 != 0){
126+
uint32_t digit = integer / power10;
127+
os << static_cast<uint32_t>(digit);
128+
integer -= power10 * (digit);
129+
power10 /= 10;
130+
}
131+
return os;
132+
}
133+
134+
135+
#endif

0 commit comments

Comments
 (0)