Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Narek/external index storage #335

Open
wants to merge 80 commits into
base: main-dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
d416092
Pull in simsimd headers only if simsimd feature is enabled
Ngalstyan4 Jan 29, 2024
61db8e5
Fix simd, openmp anf fp16 option value propagation to the compiler
Ngalstyan4 Jan 29, 2024
211a103
Fix AVX512 detection logic
Ngalstyan4 Jan 29, 2024
c4394ce
Avoid including simsimd before index_plugins
Ngalstyan4 Jan 29, 2024
c71e9c6
Fix bench_cpp binary name in benchmark documentation
Ngalstyan4 Jan 29, 2024
b10c582
Update simsimd to fix fp16 type inference
Ngalstyan4 Jan 30, 2024
1bd4842
Update SimSIMD to v3.7.5
Ngalstyan4 Jan 30, 2024
daf7ca2
Add clang-tidy clarification. todo:: is this needed?
Ngalstyan4 Dec 27, 2023
2df158c
Initial trials to move node allocation outside of index.hpp
Ngalstyan4 Dec 30, 2023
d4fb277
Move storage parameter to right before metric
Ngalstyan4 Dec 30, 2023
aac0233
Slowly moving index storage outside of index.hpp
Ngalstyan4 Dec 30, 2023
8209b52
Make external storage more functional by adding a vector storage whic…
Ngalstyan4 Dec 31, 2023
a16e11f
Move storage to a separate class and revert stats back to index
Ngalstyan4 Dec 31, 2023
76325fd
External storage with usearch working
Ngalstyan4 Jan 1, 2024
c36756b
Add size to bitset_gt
Ngalstyan4 Jan 1, 2024
9b30845
ammend to the one before the last one
Ngalstyan4 Jan 1, 2024
b78f4f9
Remove per-function call storage argument in favor of global storage
Ngalstyan4 Jan 1, 2024
ec9369a
Get rid of global storage lock
Ngalstyan4 Jan 1, 2024
7e966b5
Fix memory leaks
Ngalstyan4 Jan 2, 2024
41f6039
Rename capacity to size in added bitset_gt size
Ngalstyan4 Jan 2, 2024
c28751a
Move node sizing functions to node_t definition
Ngalstyan4 Jan 2, 2024
e2d2670
add assert and get rid of strange resizing logic
Ngalstyan4 Jan 2, 2024
d81d58d
Improve node sizing api
Ngalstyan4 Jan 2, 2024
f1b47f3
Improve node_t interface, move precompute_ inside
Ngalstyan4 Jan 2, 2024
b48a657
Clean node allocation API
Ngalstyan4 Jan 2, 2024
ee9bb58
Make storage pass-by reference for ergonimics
Ngalstyan4 Jan 2, 2024
73cf2a6
Add exchange fix an Q for Ashot
Ngalstyan4 Jan 2, 2024
731dfa2
get rid of underscores in storage function names
Ngalstyan4 Jan 2, 2024
a130ae8
Get rid of tape_allocator from index and improve dummy storage
Ngalstyan4 Jan 2, 2024
204535c
Add wip storage_v2
Ngalstyan4 Jan 2, 2024
5fdee31
Move vector storage to storage_ class
Ngalstyan4 Jan 5, 2024
6dab7ab
Move vector storage to storage_v2 and fix compile warnings
Ngalstyan4 Jan 5, 2024
3c11340
Move vectors to external storage, keep similar interface
Ngalstyan4 Jan 5, 2024
d303be1
Move storage providers to separate files
Ngalstyan4 Jan 5, 2024
0dcf791
Finish storage interface for loading from file
Ngalstyan4 Jan 5, 2024
854a11c
Fix dynamic allocation issue in storage
Ngalstyan4 Jan 5, 2024
28c9a04
Clean up Existing diff without adding any new features
Ngalstyan4 Jan 6, 2024
098f875
Fix: Make sure index to stream saving callbacks take const arguments
Ngalstyan4 Jan 6, 2024
84734d6
More high level cleanup
Ngalstyan4 Jan 6, 2024
75a3cc4
Move index load to under storage API
Ngalstyan4 Jan 6, 2024
b5d0a50
Add view() support from storage
Ngalstyan4 Jan 7, 2024
e36bd1c
Get rid of the duplicate precompute_ and use the one from node_t ever…
Ngalstyan4 Jan 7, 2024
754d9b7
Get rid of global node_head_bytes and use the equivalent node_t::head…
Ngalstyan4 Jan 7, 2024
02ecba4
Remove unnecessary code changes (comments and formatting)
Ngalstyan4 Jan 7, 2024
f26cde9
Remove compaction API for initial storage PR
Ngalstyan4 Jan 7, 2024
846355c
Remove more useless changes
Ngalstyan4 Jan 7, 2024
c42c2f7
Remove unused header
Ngalstyan4 Jan 7, 2024
f969d4e
Remove useless changes
Ngalstyan4 Jan 7, 2024
4af55fd
Attempt adding storage provider typechecking
Ngalstyan4 Jan 7, 2024
1448096
Add const-ness and noexcept enforcement to HAS_FUNCTION macro
Ngalstyan4 Jan 8, 2024
b13269e
Add helper macros for various signature assertions
Ngalstyan4 Jan 8, 2024
7717c29
Add more functions for storage API enforcement
Ngalstyan4 Jan 8, 2024
64996a7
Get rid of the old approach for API enforcement
Ngalstyan4 Jan 8, 2024
36f7109
remove last remnant of class typechecking with the old approach
Ngalstyan4 Jan 8, 2024
21f6b76
Add Storage type enforcement API comments
Ngalstyan4 Jan 8, 2024
33220d5
Add comments and add the rest of Storage interface enforcement
Ngalstyan4 Jan 8, 2024
f37bb7a
Move viewed_file_ state to storage_
Ngalstyan4 Jan 8, 2024
4291071
Fix first bug wound by typechecker
Ngalstyan4 Jan 8, 2024
08db9ec
Fix nodes_ allocator to be what in original storage_v2 it was
Ngalstyan4 Jan 8, 2024
338e2fe
Add a simple storage interface that uses std containers
Ngalstyan4 Jan 8, 2024
c6ad76d
Add storage choice to the tests
Ngalstyan4 Jan 8, 2024
25c7ca4
Cleanup and rename std storage
Ngalstyan4 Jan 8, 2024
6ff2c8f
Improve std storage code
Ngalstyan4 Jan 8, 2024
a7cc87c
Add storage argument to index_dense_gt as well
Ngalstyan4 Jan 8, 2024
d74263a
Add a note on later using node_t from storage_, instead of re-includi…
Ngalstyan4 Jan 8, 2024
69cdbdb
Add note on exchange not working with std::allocator template argument
Ngalstyan4 Jan 8, 2024
96d9c53
Add a todo on storage::memory_usage
Ngalstyan4 Jan 8, 2024
e024fca
Rename storage_v2 -> storage_v2_at
Ngalstyan4 Jan 8, 2024
9b979bd
Add a note on index_* not being movable
Ngalstyan4 Jan 9, 2024
6e11258
Rename view sub-interfaces
Ngalstyan4 Jan 9, 2024
ea5cdbb
Add setters to the enforced storage API
Ngalstyan4 Jan 9, 2024
a745439
Fix std storage commentdoc
Ngalstyan4 Jan 9, 2024
de89cef
Cleanup and improve storage naming in test.cpp
Ngalstyan4 Jan 9, 2024
72d68a0
Bugfix: make sure default storage types allocate memory with proper a…
Ngalstyan4 Jan 9, 2024
87ab073
Add proper alignment for std_storage so UBsan will not complain from …
Ngalstyan4 Jan 9, 2024
b2a3d3a
Bring back original clang-tidy
Ngalstyan4 Jan 9, 2024
c504e18
Update vectors allocator back to default since custom one has compile…
Ngalstyan4 Jan 11, 2024
8dccd68
Store storage pointer instead of storage reference in typed index to …
Ngalstyan4 Jan 14, 2024
cae7210
Add (quite questionable) move constructors
Ngalstyan4 Jan 14, 2024
ec3ed82
Initialize skiped usearch opt opts.multi
Ngalstyan4 Jan 14, 2024
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
21 changes: 6 additions & 15 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -63,18 +63,11 @@ else ()
endif ()

# Core compilation settings affecting "index.hpp"
target_compile_definitions(
${USEARCH_TARGET_NAME} INTERFACE $<$<NOT:$<BOOL:${USEARCH_USE_OPENMP}>>:USEARCH_USE_OPENMP=0>
)
target_compile_definitions(${USEARCH_TARGET_NAME} INTERFACE "USEARCH_USE_OPENMP=$<BOOL:${USEARCH_USE_OPENMP}>")

# Supplementary compilation settings affecting "index_plugins.hpp"
target_compile_definitions(
${USEARCH_TARGET_NAME} INTERFACE $<$<NOT:$<BOOL:${USEARCH_USE_FP16LIB}>>:USEARCH_USE_FP16LIB=1>
)

target_compile_definitions(
${USEARCH_TARGET_NAME} INTERFACE $<$<NOT:$<BOOL:${USEARCH_USE_SIMSIMD}>>:USEARCH_USE_SIMSIMD=0>
)
target_compile_definitions(${USEARCH_TARGET_NAME} INTERFACE "USEARCH_USE_FP16LIB=$<BOOL:${USEARCH_USE_FP16LIB}>")
target_compile_definitions(${USEARCH_TARGET_NAME} INTERFACE "USEARCH_USE_SIMSIMD=$<BOOL:${USEARCH_USE_SIMSIMD}>")

target_include_directories(
${USEARCH_TARGET_NAME} ${USEARCH_SYSTEM_INCLUDE} INTERFACE $<BUILD_INTERFACE:${USEARCH_INCLUDE_BUILD_DIR}>
Expand Down Expand Up @@ -296,14 +289,12 @@ function (setup_target TARGET_NAME)
endif ()

# Core compilation settings affecting "index.hpp"
target_compile_definitions(${TARGET_NAME} PRIVATE $<$<NOT:$<BOOL:${USEARCH_USE_OPENMP}>>:USEARCH_USE_OPENMP=0>)
target_compile_definitions(${TARGET_NAME} PRIVATE "USEARCH_USE_OPENMP=$<BOOL:${USEARCH_USE_OPENMP}>")

# Supplementary compilation settings affecting "index_plugins.hpp"
target_compile_definitions(
${TARGET_NAME} PRIVATE $<$<NOT:$<BOOL:${USEARCH_USE_FP16LIB}>>:USEARCH_USE_FP16LIB=1>
)
target_compile_definitions(${TARGET_NAME} PRIVATE "USEARCH_USE_FP16LIB=$<BOOL:${USEARCH_USE_FP16LIB}>")
target_compile_definitions(${TARGET_NAME} PRIVATE "USEARCH_USE_SIMSIMD=$<BOOL:${USEARCH_USE_SIMSIMD}>")

target_compile_definitions(${TARGET_NAME} PRIVATE $<$<NOT:$<BOOL:${USEARCH_USE_SIMSIMD}>>:USEARCH_USE_SIMSIMD=0>)

endfunction ()

Expand Down
1 change: 1 addition & 0 deletions c/test.c
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ usearch_init_options_t create_options(size_t const dimensions) {
opts.dimensions = dimensions;
opts.expansion_add = 40; // 40 in faiss
opts.expansion_search = 16; // 10 in faiss
opts.multi = false;
opts.metric_kind = usearch_metric_ip_k;
opts.metric = NULL;
opts.quantization = usearch_scalar_f32_k;
Expand Down
4 changes: 1 addition & 3 deletions cpp/bench.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,6 @@
#include <omp.h> // `omp_set_num_threads()`
#endif

#include <simsimd/simsimd.h>

#include <usearch/index_dense.hpp>

using namespace unum::usearch;
Expand Down Expand Up @@ -615,4 +613,4 @@ int main(int argc, char** argv) {
run_punned<index_dense_gt<default_key_t, std::uint32_t>>(dataset, args, config, limits);

return 0;
}
}
40 changes: 29 additions & 11 deletions cpp/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@
#include <cassert> // `assert`
#include <random> // `std::default_random_engine`
#include <stdexcept>
#include <unordered_map>
#include <vector> // for std::vector

#include <usearch/index.hpp>
#include <usearch/index_dense.hpp>
#include <usearch/index_plugins.hpp>
#include <usearch/std_storage.hpp>

using namespace unum::usearch;
using namespace unum;
Expand Down Expand Up @@ -77,7 +77,7 @@ void test_cosine(index_at& index, std::vector<std::vector<scalar_at>> const& vec
expect((index.stats(0).nodes == 3));

// Check if clustering endpoint compiles
index.cluster(vector_first, 0, args...);
// index.cluster(vector_first, 0, args...);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

storage interface has not yet been added for this endpoint, so I removed the test.
Will add it back when implemented


// Try removals and replacements
if constexpr (punned_ak) {
Expand Down Expand Up @@ -141,8 +141,8 @@ void test_cosine(index_at& index, std::vector<std::vector<scalar_at>> const& vec
index.get(key_second, vec_recovered_from_view.data());
expect(std::equal(vector_second, vector_second + dimensions, vec_recovered_from_view.data()));

auto compaction_result = index.compact();
expect(bool(compaction_result));
// auto compaction_result = index.compact();
// expect(bool(compaction_result));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

}

expect(index.memory_usage() > 0);
Expand All @@ -155,14 +155,15 @@ void test_cosine(index_at& index, std::vector<std::vector<scalar_at>> const& vec
}
}

template <typename scalar_at, typename key_at, typename slot_at> //
template <typename storage_at, typename scalar_at, typename key_at, typename slot_at> //
void test_cosine(std::size_t collection_size, std::size_t dimensions) {

using storage_t = storage_at;
using scalar_t = scalar_at;
using vector_key_t = key_at;
using slot_t = slot_at;

using index_typed_t = index_gt<float, vector_key_t, slot_t>;
using index_typed_t = index_gt<storage_t, float, vector_key_t, slot_t>;
using member_cref_t = typename index_typed_t::member_cref_t;
using member_citerator_t = typename index_typed_t::member_citerator_t;

Expand Down Expand Up @@ -197,15 +198,17 @@ void test_cosine(std::size_t collection_size, std::size_t dimensions) {
std::printf("- templates with connectivity %zu \n", connectivity);
metric_t metric{&matrix, dimensions};
index_config_t config(connectivity);
index_typed_t index_typed(config);
storage_t storage{config};
index_typed_t index_typed_tmp(&storage, config);
index_typed_t index_typed = std::move(index_typed_tmp);
test_cosine<false>(index_typed, matrix, metric);
}

// Type-punned:
for (bool multi : {false, true}) {
for (std::size_t connectivity : {3, 13, 50}) {
std::printf("- punned with connectivity %zu \n", connectivity);
using index_t = index_dense_gt<vector_key_t, slot_t>;
using index_t = index_dense_gt<vector_key_t, slot_t, storage_t>;
metric_punned_t metric(dimensions, metric_kind_t::cos_k, scalar_kind<scalar_at>());
index_dense_config_t config(connectivity);
config.multi = multi;
Expand Down Expand Up @@ -310,9 +313,24 @@ int main(int, char**) {
for (std::size_t collection_size : {10, 500})
for (std::size_t dimensions : {97, 256}) {
std::printf("Indexing %zu vectors with cos: <float, std::int64_t, std::uint32_t> \n", collection_size);
test_cosine<float, std::int64_t, std::uint32_t>(collection_size, dimensions);
std::printf("Indexing %zu vectors with cos: <float, std::int64_t, uint40_t> \n", collection_size);
test_cosine<float, std::int64_t, uint40_t>(collection_size, dimensions);
using key_t = std::int64_t;
{
using slot_t = std::uint32_t;
using storage_v2_t = storage_v2_at<key_t, slot_t>;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Runs tests for the two storage provider APIs

storage_v2_t is the current storage interface, rearranged into a separate API
std_storage_t is an example storage provider that demonstrates the API use.
It stores all data in std:: containers and serializes data to disk similar to usearch v1.
it does not do error handling (asserts all errors

using std_storage_t = std_storage_at<key_t, slot_t>;

test_cosine<storage_v2_t, float, std::int64_t, std::uint32_t>(collection_size, dimensions);
test_cosine<std_storage_t, float, std::int64_t, std::uint32_t>(collection_size, dimensions);
}
{
using slot_t = uint40_t;
using storage_v2_t = storage_v2_at<key_t, slot_t>;
using std_storage_t = std_storage_at<key_t, slot_t>;

std::printf("Indexing %zu vectors with cos: <float, std::int64_t, uint40_t> \n", collection_size);
test_cosine<storage_v2_t, float, key_t, slot_t>(collection_size, dimensions);
test_cosine<std_storage_t, float, key_t, slot_t>(collection_size, dimensions);
}
}

for (std::size_t connectivity : {3, 13, 50})
Expand Down
23 changes: 12 additions & 11 deletions docs/benchmarks.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ Also worth noting, 8-bit quantization results in almost no quantization loss and

Within this repository you will find two commonly used utilities:

- `cpp/bench.cpp` the produces the `bench` binary for broad USearch benchmarks.
- `cpp/bench.cpp` the produces the `bench_cpp` binary for broad USearch benchmarks.
- `python/bench.py` and `python/bench.ipynb` for interactive charts against FAISS.

To achieve best highest results we suggest compiling locally for the target architecture.
Expand All @@ -64,17 +64,19 @@ To achieve best highest results we suggest compiling locally for the target arch
cmake -B ./build_release \
-DCMAKE_BUILD_TYPE=Release \
-DUSEARCH_USE_OPENMP=1 \
-DUSEARCH_USE_SIMSIMD=1 \
-DUSEARCH_USE_FP16LIB=0 \
-DUSEARCH_USE_JEMALLOC=1 && \
make -C ./build_release -j

./build_release/bench --help
./build_release/bench_cpp --help
```

Which would print the following instructions.

```txt
SYNOPSIS
./build_release/bench [--vectors <path>] [--queries <path>] [--neighbors <path>] [-b] [-j
./build_release/bench_cpp [--vectors <path>] [--queries <path>] [--neighbors <path>] [-b] [-j
<integer>] [-c <integer>] [--expansion-add <integer>]
[--expansion-search <integer>] [--native|--f16quant|--i8quant]
[--ip|--l2sq|--cos|--haversine] [-h]
Expand Down Expand Up @@ -115,12 +117,12 @@ OPTIONS
Here is an example of running the C++ benchmark:

```sh
./build_release/bench \
./build_release/bench_cpp \
--vectors datasets/wiki_1M/base.1M.fbin \
--queries datasets/wiki_1M/query.public.100K.fbin \
--neighbors datasets/wiki_1M/groundtruth.public.100K.ibin

./build_release/bench \
./build_release/bench_cpp \
--vectors datasets/t2i_1B/base.1B.fbin \
--queries datasets/t2i_1B/query.public.100K.fbin \
--neighbors datasets/t2i_1B/groundtruth.public.100K.ibin \
Expand Down Expand Up @@ -205,17 +207,17 @@ With `perf`:

```sh
# Pass environment variables with `-E`, and `-d` for details
sudo -E perf stat -d ./build_release/bench ...
sudo -E perf mem -d ./build_release/bench ...
sudo -E perf stat -d ./build_release/bench_cpp ...
sudo -E perf mem -d ./build_release/bench_cpp ...
# Sample on-CPU functions for the specified command, at 1 Kilo Hertz:
sudo -E perf record -F 1000 ./build_release/bench ...
perf record -d -e arm_spe// -- ./build_release/bench ..
sudo -E perf record -F 1000 ./build_release/bench_cpp ...
perf record -d -e arm_spe// -- ./build_release/bench_cpp ..
```

### Caches

```sh
sudo perf stat -e 'faults,dTLB-loads,dTLB-load-misses,cache-misses,cache-references' ./build_release/bench ...
sudo perf stat -e 'faults,dTLB-loads,dTLB-load-misses,cache-misses,cache-references' ./build_release/bench_cpp ...
```

Typical output on a 1M vectors dataset is:
Expand All @@ -242,4 +244,3 @@ sudo sysctl -w vm.nr_hugepages=2048
sudo reboot
sudo cat /proc/sys/vm/nr_hugepages
```

Loading
Loading