Skip to content
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
47 commits
Select commit Hold shift + click to select a range
3c40a06
Init IVFPQ migration
lowener Apr 11, 2024
c5a3d3a
Migrate ivf-pq build steps to cuvs
lowener Apr 15, 2024
3568f12
Migrate ivf-pq extend to cuvs
lowener Apr 15, 2024
69bf330
Migrate ivf-pq serialize to cuvs
lowener Apr 16, 2024
7a5e8a0
Migrate compute similarity
lowener Apr 17, 2024
4b86f94
Migrate search
lowener Apr 18, 2024
8c8aaed
Add Test for IVFPQ
lowener Apr 19, 2024
e444f4b
Temporarily remove IVFPQ Search with filter
lowener Apr 19, 2024
5228a68
Reset exceptions
lowener Apr 19, 2024
3f924f2
Merge branch 'branch-24.06' into 24.06-ivfpq-migration
lowener Apr 19, 2024
e8907ee
Add bitset to cuvs, add search_with_filter to ivf-pq
lowener Apr 23, 2024
64809e8
Remove `uint32_t` ivfpq compute_similarity instantiation
lowener Apr 23, 2024
e88f82c
Add bitset to compute similarity instantiation
lowener Apr 23, 2024
36bd63b
Add NVTX cuvs domain
lowener Apr 24, 2024
9c4781d
Expose only public API on includes
lowener Apr 30, 2024
9cbfc53
First commit of moving CAGRA from RAFT
cjnolet Apr 30, 2024
1a8a789
Making progress
cjnolet May 1, 2024
6e7591a
Merge branch 'branch-24.06' into 24.06-ivfpq-migration
cjnolet May 1, 2024
5a719ba
Move headers
lowener May 3, 2024
844f209
Merge remote-tracking branch 'mickael/24.06-ivfpq-migration' into fea…
cjnolet May 3, 2024
2783c83
Making progress
cjnolet May 3, 2024
ec2125b
Checking in.
cjnolet May 3, 2024
c024780
COuple minor fixes to ann_utils
cjnolet May 3, 2024
55d8851
More fixes to ann_utils
cjnolet May 3, 2024
b24a43c
MOre updates
cjnolet May 4, 2024
091fe02
Separate header and impl for filters
lowener May 6, 2024
80a0c0b
Compiles!
cjnolet May 6, 2024
40a860a
Merge remote-tracking branch 'mickael/24.06-ivfpq-migration' into fea…
cjnolet May 6, 2024
cb011f6
I think it works!
cjnolet May 6, 2024
dff10bc
Making sure tests are using runtime APIs
cjnolet May 6, 2024
3a4c04b
Merge branch 'branch-24.06' into fea-2406-cagra_from_raft
cjnolet May 6, 2024
8fd2389
Removing debugging prints
cjnolet May 6, 2024
9b9db71
Checking in
cjnolet May 6, 2024
e5b8500
Merge branch 'fea-2406-cagra_from_raft' of github.com:rapidsai/cuvs i…
cjnolet May 6, 2024
849358c
Adding nn-descent public API and tests
cjnolet May 6, 2024
8621e6f
Fix style
lowener May 8, 2024
197730e
Remove CMAKE_INSTALL_MESSAGE = LAZY
lowener May 8, 2024
7c15d0c
Merge remote-tracking branch 'mickael/24.06-ivfpq-migration' into fea…
cjnolet May 8, 2024
5b60ee4
Fixing docs
cjnolet May 8, 2024
73ae071
Using CUVS_USE_RAFT_STATIC
cjnolet May 9, 2024
57d33a8
Trying again
cjnolet May 9, 2024
3cf245a
Trying again...y
cjnolet May 9, 2024
f7dbd55
Use Raft Bitset
lowener May 10, 2024
e22aff7
Revert "Trying again...y"
cjnolet May 10, 2024
de395c8
Revert "Using CUVS_USE_RAFT_STATIC"
cjnolet May 10, 2024
5239b93
Making sure the python cmakelists is reverted
cjnolet May 10, 2024
10b9a7e
Removing line that was accidentally inserted back
cjnolet May 10, 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
2 changes: 1 addition & 1 deletion build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ INSTALL_TARGET=install
BUILD_REPORT_METRICS=""
BUILD_REPORT_INCL_CACHE_STATS=OFF

TEST_TARGETS="NEIGHBORS_ANN_CAGRA_TEST"
TEST_TARGETS="NEIGHBORS_ANN_CAGRA_TEST;CORE_TEST"

CACHE_ARGS=""
NVTX=ON
Expand Down
41 changes: 31 additions & 10 deletions cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ project(
VERSION "${RAPIDS_VERSION}"
LANGUAGES ${lang_list}
)
set(CMAKE_INSTALL_MESSAGE LAZY)

# Write the version header
rapids_cmake_write_version_file(include/cuvs/version_config.hpp)
Expand Down Expand Up @@ -188,6 +189,7 @@ include(cmake/thirdparty/get_cutlass.cmake)

add_library(
cuvs SHARED
src/core/bitset.cu
src/neighbors/brute_force_index.cu
src/neighbors/brute_force.cu
src/neighbors/cagra_build_float.cpp
Expand All @@ -214,16 +216,35 @@ add_library(
src/neighbors/ivf_flat/ivf_flat_serialize_int8_t_int64_t.cpp
src/neighbors/ivf_flat/ivf_flat_serialize_uint8_t_int64_t.cpp
src/neighbors/ivf_pq_index.cpp
src/neighbors/ivf_pq/ivf_pq_build_float_int64_t.cpp
src/neighbors/ivf_pq/ivf_pq_build_int8_t_int64_t.cpp
src/neighbors/ivf_pq/ivf_pq_build_uint8_t_int64_t.cpp
src/neighbors/ivf_pq/ivf_pq_extend_float_int64_t.cpp
src/neighbors/ivf_pq/ivf_pq_extend_int8_t_int64_t.cpp
src/neighbors/ivf_pq/ivf_pq_extend_uint8_t_int64_t.cpp
src/neighbors/ivf_pq/ivf_pq_search_float_int64_t.cpp
src/neighbors/ivf_pq/ivf_pq_search_int8_t_int64_t.cpp
src/neighbors/ivf_pq/ivf_pq_search_uint8_t_int64_t.cpp
src/neighbors/ivf_pq_serialize.cpp
src/neighbors/ivf_pq/ivf_pq_build_common.cu
src/neighbors/ivf_pq/ivf_pq_build_float_int64_t.cu
src/neighbors/ivf_pq/ivf_pq_build_int8_t_int64_t.cu
src/neighbors/ivf_pq/ivf_pq_build_uint8_t_int64_t.cu
src/neighbors/ivf_pq/ivf_pq_compute_similarity_half_fp8_false.cu
src/neighbors/ivf_pq/ivf_pq_compute_similarity_half_fp8_true.cu
src/neighbors/ivf_pq/ivf_pq_compute_similarity_half_half.cu
src/neighbors/ivf_pq/ivf_pq_compute_similarity_float_half.cu
src/neighbors/ivf_pq/ivf_pq_compute_similarity_float_float.cu
src/neighbors/ivf_pq/ivf_pq_compute_similarity_float_fp8_false.cu
src/neighbors/ivf_pq/ivf_pq_compute_similarity_float_fp8_true.cu
src/neighbors/ivf_pq/ivf_pq_compute_similarity_half_fp8_false_bitset64.cu
src/neighbors/ivf_pq/ivf_pq_compute_similarity_half_fp8_true_bitset64.cu
src/neighbors/ivf_pq/ivf_pq_compute_similarity_half_half_bitset64.cu
src/neighbors/ivf_pq/ivf_pq_compute_similarity_float_half_bitset64.cu
src/neighbors/ivf_pq/ivf_pq_compute_similarity_float_float_bitset64.cu
src/neighbors/ivf_pq/ivf_pq_compute_similarity_float_fp8_false_bitset64.cu
src/neighbors/ivf_pq/ivf_pq_compute_similarity_float_fp8_true_bitset64.cu
src/neighbors/ivf_pq/ivf_pq_deserialize.cu
src/neighbors/ivf_pq/ivf_pq_extend_float_int64_t.cu
src/neighbors/ivf_pq/ivf_pq_extend_int8_t_int64_t.cu
src/neighbors/ivf_pq/ivf_pq_extend_uint8_t_int64_t.cu
src/neighbors/ivf_pq/ivf_pq_search_float_int64_t.cu
src/neighbors/ivf_pq/ivf_pq_search_int8_t_int64_t.cu
src/neighbors/ivf_pq/ivf_pq_search_uint8_t_int64_t.cu
src/neighbors/ivf_pq/ivf_pq_search_with_filter_float_int64_t.cu
src/neighbors/ivf_pq/ivf_pq_search_with_filter_int8_t_int64_t.cu
src/neighbors/ivf_pq/ivf_pq_search_with_filter_uint8_t_int64_t.cu
src/neighbors/ivf_pq/ivf_pq_serialize.cu
)

target_compile_options(
Expand Down
264 changes: 264 additions & 0 deletions cpp/include/cuvs/core/bitset.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
/*
* Copyright (c) 2024, NVIDIA CORPORATION.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We should consider keeping this in raft with the other vocabulary types so it can continue to be used across different libraries that use raft. Also- we can't be defining device functions in an hpp file in cuVS, since it's not header-only. The only APIs users should be interacting with in cuVS should be pre-compiled runtime APIs.

* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#pragma once

#include <raft/core/device_container_policy.hpp>
#include <raft/core/device_mdarray.hpp>
#include <raft/core/resource/thrust_policy.hpp>
#include <raft/core/resources.hpp>
#include <thrust/functional.h>

namespace cuvs::core {
/**
* @defgroup bitset Bitset
* @{
*/
/**
* @brief View of a cuVS Bitset.
*
* This lightweight structure stores a pointer to a bitset in device memory with it's length.
* It provides a test() device function to check if a given index is set in the bitset.
*
* @tparam bitset_t Underlying type of the bitset array. Default is uint32_t.
* @tparam index_t Indexing type used. Default is uint32_t.
*/
template <typename bitset_t = uint32_t, typename index_t = uint32_t>
struct bitset_view {
static constexpr index_t bitset_element_size = sizeof(bitset_t) * 8;

_RAFT_HOST_DEVICE bitset_view(bitset_t* bitset_ptr, index_t bitset_len);
/**
* @brief Create a bitset view from a device vector view of the bitset.
*
* @param bitset_span Device vector view of the bitset
* @param bitset_len Number of bits in the bitset
*/
_RAFT_HOST_DEVICE bitset_view(raft::device_vector_view<bitset_t, index_t> bitset_span,
index_t bitset_len);
/**
* @brief Device function to test if a given index is set in the bitset.
*
* @param sample_index Single index to test
* @return bool True if index has not been unset in the bitset
*/
_RAFT_DEVICE inline bool test(const index_t sample_index) const
{
const bitset_t bit_element = bitset_ptr_[sample_index / bitset_element_size];
const index_t bit_index = sample_index % bitset_element_size;
const bool is_bit_set = (bit_element & (bitset_t{1} << bit_index)) != 0;
return is_bit_set;
}
/**
* @brief Device function to test if a given index is set in the bitset.
*
* @param sample_index Single index to test
* @return bool True if index has not been unset in the bitset
*/
_RAFT_DEVICE bool operator[](const index_t sample_index) const { return test(sample_index); }
/**
* @brief Device function to set a given index to set_value in the bitset.
*
* @param sample_index index to set
* @param set_value Value to set the bit to (true or false)
*/
_RAFT_DEVICE void set(const index_t sample_index, bool set_value) const;

/**
* @brief Get the device pointer to the bitset.
*/
_RAFT_HOST_DEVICE bitset_t* data();
_RAFT_HOST_DEVICE const bitset_t* data() const;
/**
* @brief Get the number of bits of the bitset representation.
*/
_RAFT_HOST_DEVICE index_t size() const;

/**
* @brief Get the number of elements used by the bitset representation.
*/
_RAFT_HOST_DEVICE index_t n_elements() const;

raft::device_vector_view<bitset_t, index_t> to_mdspan();
raft::device_vector_view<const bitset_t, index_t> to_mdspan() const;

private:
bitset_t* bitset_ptr_;
index_t bitset_len_;
};

/**
* @brief cuVS Bitset.
*
* This structure encapsulates a bitset in device memory. It provides a view() method to get a
* device-usable lightweight view of the bitset.
* Each index is represented by a single bit in the bitset. The total number of bytes used is
* ceil(bitset_len / 8).
* @tparam bitset_t Underlying type of the bitset array. Default is uint32_t.
* @tparam index_t Indexing type used. Default is uint32_t.
*/
template <typename bitset_t = uint32_t, typename index_t = uint32_t>
struct bitset {
static constexpr index_t bitset_element_size = sizeof(bitset_t) * 8;

/**
* @brief Construct a new bitset object with a list of indices to unset.
*
* @param res RAFT resources
* @param mask_index List of indices to unset in the bitset
* @param bitset_len Length of the bitset
* @param default_value Default value to set the bits to. Default is true.
*/
bitset(const raft::resources& res,
raft::device_vector_view<const index_t, index_t> mask_index,
index_t bitset_len,
bool default_value = true);

/**
* @brief Construct a new bitset object
*
* @param res RAFT resources
* @param bitset_len Length of the bitset
* @param default_value Default value to set the bits to. Default is true.
*/
bitset(const raft::resources& res, index_t bitset_len, bool default_value = true);
// Disable copy constructor
bitset(const bitset&) = delete;
bitset(bitset&&) = default;
bitset& operator=(const bitset&) = delete;
bitset& operator=(bitset&&) = default;

/**
* @brief Create a device-usable view of the bitset.
*
* @return bitset_view<bitset_t, index_t>
*/
cuvs::core::bitset_view<bitset_t, index_t> view();
cuvs::core::bitset_view<const bitset_t, index_t> view() const;

/**
* @brief Get the device pointer to the bitset.
*/
bitset_t* data();
const bitset_t* data() const;
/**
* @brief Get the number of bits of the bitset representation.
*/
index_t size() const;

/**
* @brief Get the number of elements used by the bitset representation.
*/
index_t n_elements() const;

/** @brief Get an mdspan view of the current bitset */
raft::device_vector_view<bitset_t, index_t> to_mdspan();
raft::device_vector_view<const bitset_t, index_t> to_mdspan() const;

/** @brief Resize the bitset. If the requested size is larger, new memory is allocated and set to
* the default value.
* @param res RAFT resources
* @param new_bitset_len new size of the bitset
* @param default_value default value to initialize the new bits to
*/
void resize(const raft::resources& res, index_t new_bitset_len, bool default_value = true);

/**
* @brief Test a list of indices in a bitset.
*
* @tparam output_t Output type of the test. Default is bool.
* @param res RAFT resources
* @param queries List of indices to test
* @param output List of outputs
*/
/*
TODO: Disabled test() for cuVS migration
template <typename output_t = bool>
void test(const raft::resources& res,
raft::device_vector_view<const index_t, index_t> queries,
raft::device_vector_view<output_t, index_t> output) const
{
RAFT_EXPECTS(output.extent(0) == queries.extent(0), "Output and queries must be same size");
auto bitset_view = view();
thrust::transform(
raft::resource::get_thrust_policy(res),
queries.data_handle(),
queries.data_handle() + queries.size(),
output.data_handle(),
[bitset_view] __device__(index_t query) { return output_t{bitset_view.test(query)}; });
}
*/
/**
* @brief Set a list of indices in a bitset to set_value.
*
* @param res RAFT resources
* @param mask_index indices to remove from the bitset
* @param set_value Value to set the bits to (true or false)
*/
void set(const raft::resources& res,
raft::device_vector_view<const index_t, index_t> mask_index,
bool set_value = false);
/**
* @brief Flip all the bits in a bitset.
* @param res RAFT resources
*/
void flip(const raft::resources& res);
/**
* @brief Reset the bits in a bitset.
*
* @param res RAFT resources
* @param default_value Value to set the bits to (true or false)
*/
void reset(const raft::resources& res, bool default_value = true);
/**
* @brief Returns the number of bits set to true in count_gpu_scalar.
*
* @param[in] res RAFT resources
* @param[out] count_gpu_scalar Device scalar to store the count
*/
void count(const raft::resources& res, raft::device_scalar_view<index_t> count_gpu_scalar);

/**
* @brief Returns the number of bits set to true.
*
* @param res RAFT resources
* @return index_t Number of bits set to true
*/
index_t count(const raft::resources& res);

/**
* @brief Checks if any of the bits are set to true in the bitset.
* @param res RAFT resources
*/
bool any(const raft::resources& res) { return count(res) > 0; }
/**
* @brief Checks if all of the bits are set to true in the bitset.
* @param res RAFT resources
*/
bool all(const raft::resources& res) { return count(res) == bitset_len_; }
/**
* @brief Checks if none of the bits are set to true in the bitset.
* @param res RAFT resources
*/
bool none(const raft::resources& res) { return count(res) == 0; }

private:
raft::device_uvector<bitset_t> bitset_;
index_t bitset_len_;
};

/** @} */
} // end namespace cuvs::core
25 changes: 25 additions & 0 deletions cpp/include/cuvs/core/nvtx.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/*
* Copyright (c) 2024, NVIDIA CORPORATION.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This shouldn't be a user-facing API and thus shouldn't be defined in include/. We should no longer be using include/ for headers just because they need to be used across cuvs. Use src/ for those headers. Only headers in include/ should be those that we expect the user to interact with directly (thus the number of headers in include/ should be very small.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Having all of the declaration in src/ will lead to #include with long relative paths that can be problematic in the future.
To avoid that we can add the src/ directory to CMake target_include_directories() but this would lead to includes such as src/core/nvtx.hpp. Are we fine with that or do we want to keep something like cuvs/core/nvtx.hpp?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I've done relative paths for cagra so far and haven't seen them to be too terrible. Is ivf-pq somehow making it more challenging to work with?

From a development perspective, I generally tend to prefer the use of the relative quotationed paths for things that are local to src/, (and thus internal) rather than muddying the line between the two and making it harder to discern which things are public APIs and which aren't.

*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#pragma once
#include <raft/core/nvtx.hpp>

namespace cuvs::common::nvtx::domain {
/** @brief This NVTX domain is supposed to be used within cuvs. */
struct cuvs {
static constexpr const char* name = "cuvs";
};
}; // namespace cuvs::common::nvtx::domain
Loading