Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
8b98037
Forwarding all the previous work
vinaydes Jan 27, 2026
316df9f
Removing and updating comments
vinaydes Jan 28, 2026
4276494
RNG does not support int8_t, therefore commenting the test case for now
vinaydes Jan 28, 2026
c36f25e
Adding cutlass dependency to the benchmarking code
vinaydes Jan 28, 2026
f5ed1c7
Removing unused API declaration
vinaydes Jan 29, 2026
268a505
Fixing Blackwell's SM version
vinaydes Jan 29, 2026
381653f
Removing debugging and profiling code
vinaydes Jan 29, 2026
7a49bec
Splitting the GEMM and reduction calls
vinaydes Jan 29, 2026
f5a8a79
Updating the name of distance GEMM cal
vinaydes Jan 29, 2026
5a4a795
Changing the file name to reflect the benchmark better
vinaydes Jan 29, 2026
1b372fe
Updating the name of benchmarking file
vinaydes Feb 2, 2026
9e9e912
Updating test and bench file names
vinaydes Feb 2, 2026
8aff3dd
Changed to manual time to capture correct GPU time
vinaydes Feb 3, 2026
0384953
Adding default benchmarking cases and refactoring
vinaydes Feb 3, 2026
6aa6b4a
Refactoring
vinaydes Feb 3, 2026
e65cd9a
Improving comments and refactoring
vinaydes Feb 3, 2026
d653bce
Removing unused headers
vinaydes Feb 3, 2026
f0108df
Merge branch 'main' into distance-nn
vinaydes Feb 4, 2026
124cce6
Merge branch 'main' into distance-nn
vinaydes Feb 10, 2026
381ac80
Correcting the constant type for int8_t gemm
vinaydes Feb 12, 2026
2874b41
Enable int8_t test cases
vinaydes Feb 12, 2026
84dbca1
Removing redundant constant declarations
vinaydes Feb 13, 2026
36f346b
Replacing the stream sync call
vinaydes Feb 13, 2026
6754290
Formatting
vinaydes Feb 13, 2026
2aebd6c
Merge branch 'main' into distance-nn
vinaydes Feb 16, 2026
aefe91b
Apply suggestions from code review
vinaydes Feb 19, 2026
5c31c28
Update cpp/bench/prims/src/distance/distance_nn.cu
vinaydes Feb 19, 2026
2c2196a
Always assume GPU build
vinaydes Feb 19, 2026
7e8afc0
Add test cases where m != n
vinaydes Feb 19, 2026
1bd407f
Replacing with matrix::fill
vinaydes Feb 23, 2026
bef16b5
Using RAFT host device function macro
vinaydes Feb 23, 2026
e6f861b
Varying some more sizes
vinaydes Feb 23, 2026
4cdf49e
Fixing the dimension of vectors
vinaydes Feb 23, 2026
d957b33
Merge branch 'main' into distance-nn
vinaydes Feb 24, 2026
ec3487d
Merge branch 'main' into distance-nn
vinaydes Mar 3, 2026
c5b51e0
Merge branch 'main' into distance-nn
aamijar Mar 4, 2026
f522203
Merge branch 'main' into distance-nn
cjnolet Mar 5, 2026
afa39a2
Merge branch 'main' into distance-nn
vinaydes Mar 20, 2026
31d1def
Deleting warm-up as warm-up runs can be done using google benchmark cli
vinaydes Mar 20, 2026
0790c56
CUB block reduce header needs to be exclusively included now
vinaydes Mar 20, 2026
1324a1d
Adding docstring to explain the reduction function
vinaydes Mar 20, 2026
5e355fa
Explicity setting stream for cublas gemm
vinaydes Mar 20, 2026
3313834
Removing the prims benchmarks for now
vinaydes Mar 20, 2026
3a4dfaf
Fixing a spelling error
vinaydes Mar 20, 2026
7a2e1a2
Merge branch 'main' into distance-nn
vinaydes Apr 7, 2026
911686a
Merge branch 'main' into distance-nn
vinaydes May 5, 2026
15b242d
Removing unintentional whitespace change
vinaydes May 6, 2026
43e7e93
Adding a grid-strided loop to cover full array length
vinaydes May 6, 2026
d622448
Fixing the grid-strided loop
vinaydes May 6, 2026
39b0259
Adding a seed_offset to generate different x an y vectors
vinaydes May 6, 2026
0e3cb11
Fixing the issue with cosine norm computation
vinaydes May 6, 2026
8472fe1
Syncing before comparing
vinaydes May 6, 2026
6f35fa7
Adding tests for L2SqrtExpanded
vinaydes May 6, 2026
c80051e
Update batch size calculation
vinaydes May 6, 2026
73e19da
Adding error check for CUDA kernel launch failures
vinaydes May 6, 2026
c4cfc69
Making sure that all dimensions are non-zero before starting the dist…
vinaydes May 6, 2026
b67dda6
Minor and formatting changes
vinaydes May 6, 2026
e8d6bd1
Adding guards for zero-norm vectors
vinaydes May 6, 2026
63e0796
Merge branch 'main' into distance-nn
tfeher May 7, 2026
89a1640
Merge branch 'main' into distance-nn
vinaydes May 11, 2026
4104e5f
Merge remote-tracking branch 'work-github/distance-nn' into distance-nn
vinaydes May 11, 2026
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
31 changes: 19 additions & 12 deletions cpp/src/cluster/detail/kmeans_balanced.cuh
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <raft/core/operators.hpp>
#include <raft/core/resource/cuda_stream.hpp>
#include <raft/core/resource/device_memory_resource.hpp>
#include <raft/core/resource/device_properties.hpp>
#include <raft/core/resource/thrust_policy.hpp>
#include <raft/linalg/add.cuh>
#include <raft/linalg/gemm.cuh>
Expand Down Expand Up @@ -171,22 +172,28 @@ inline std::enable_if_t<std::is_floating_point_v<MathT>> predict_core(
* @return A suggested minibatch size and the expected memory cost per-row (in bytes)
*/
template <typename MathT, typename IdxT>
constexpr auto calc_minibatch_size(IdxT n_clusters,
IdxT n_rows,
IdxT dim,
cuvs::distance::DistanceType metric,
bool needs_conversion) -> std::tuple<IdxT, size_t>
auto calc_minibatch_size(const raft::resources& handle,
IdxT n_clusters,
IdxT n_rows,
IdxT dim,
cuvs::distance::DistanceType metric,
bool needs_conversion) -> std::tuple<IdxT, size_t>
{
n_clusters = std::max<IdxT>(1, n_clusters);

// Estimate memory needs per row (i.e element of the batch).
size_t mem_per_row = 0;
switch (metric) {
// fusedL2NN needs a mutex and a key-value pair for each row.
case distance::DistanceType::L2Expanded:
case distance::DistanceType::L2SqrtExpanded: {
mem_per_row += sizeof(int);
mem_per_row += sizeof(raft::KeyValuePair<IdxT, MathT>);
if (use_fused<MathT, IdxT, IdxT>(handle, n_rows, n_clusters, dim)) {
// fusedL2NN needs a mutex and a key-value pair for each row.
mem_per_row += sizeof(int);
mem_per_row += sizeof(raft::KeyValuePair<IdxT, MathT>);
} else {
// unfused path needs a full GEMM output (distance matrix row).
mem_per_row += sizeof(MathT) * n_clusters;
}
} break;
// Other metrics require storing a distance matrix.
default: {
Expand Down Expand Up @@ -377,8 +384,8 @@ void predict(const raft::resources& handle,
raft::common::nvtx::range<cuvs::common::nvtx::domain::cuvs> fun_scope(
"predict(%zu, %u)", static_cast<size_t>(n_rows), n_clusters);
auto mem_res = mr.value_or(raft::resource::get_workspace_resource_ref(handle));
auto [max_minibatch_size, _mem_per_row] =
calc_minibatch_size<MathT>(n_clusters, n_rows, dim, params.metric, std::is_same_v<T, MathT>);
auto [max_minibatch_size, _mem_per_row] = calc_minibatch_size<MathT>(
handle, n_clusters, n_rows, dim, params.metric, std::is_same_v<T, MathT>);
rmm::device_uvector<MathT> cur_dataset(
std::is_same_v<T, MathT> ? 0 : max_minibatch_size * dim, stream, mem_res);
bool need_compute_norm =
Expand Down Expand Up @@ -989,8 +996,8 @@ void build_hierarchical(const raft::resources& handle,
// TODO: Remove the explicit managed memory- we shouldn't be creating this on the user's behalf.
rmm::mr::managed_memory_resource managed_memory;
rmm::device_async_resource_ref device_memory = raft::resource::get_workspace_resource_ref(handle);
auto [max_minibatch_size, mem_per_row] =
calc_minibatch_size<MathT>(n_clusters, n_rows, dim, params.metric, std::is_same_v<T, MathT>);
auto [max_minibatch_size, mem_per_row] = calc_minibatch_size<MathT>(
handle, n_clusters, n_rows, dim, params.metric, std::is_same_v<T, MathT>);

// Precompute the L2 norm of the dataset if relevant and not yet computed.
rmm::device_uvector<MathT> dataset_norm_buf(0, stream, device_memory);
Expand Down
26 changes: 26 additions & 0 deletions cpp/src/cluster/detail/kmeans_common.cuh
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
#include <raft/core/memory_type.hpp>
#include <raft/core/operators.hpp>
#include <raft/core/resource/cuda_stream.hpp>
#include <raft/core/resource/device_properties.hpp>
#include <raft/core/resource/thrust_policy.hpp>
#include <raft/core/resources.hpp>
#include <raft/linalg/map.cuh>
Expand Down Expand Up @@ -56,6 +57,31 @@

namespace cuvs::cluster::kmeans::detail {

/**
* @brief Returns true if the fused distance NN implementation should be used.
*
* On Ampere (SM <= 8.x) always use fused.
* On Hopper (SM 9.x) use fused when m or n >= 4096.
* On Blackwell (SM >= 10.x) use unfused.
*/
template <typename MathT, typename IdxT, typename LabelT>
bool use_fused(const raft::resources& handle, IdxT m, IdxT n, IdxT k)
{
cudaDeviceProp prop;
prop = raft::resource::get_device_properties(handle);
if (prop.major <= 8) {
// Use fused for Ampere or before
return true;
} else if (prop.major == 9 && (m >= 4096 || n >= 4096)) {
// On Hopper if m, n are bigger than 4096, use fused
return true;
} else if (prop.major >= 10) {
// On Blackwell onwards, use unfused
return false;
}
return false;
}
Comment thread
vinaydes marked this conversation as resolved.

template <typename DataT, typename IndexT>
struct SamplingOp {
DataT* rnd;
Expand Down
63 changes: 45 additions & 18 deletions cpp/src/cluster/detail/minClusterDistanceCompute.cu
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

#include "../../distance/fused_distance_nn.cuh"
#include "../../distance/unfused_distance_nn.cuh"
#include "kmeans_common.cuh"

#include <raft/matrix/init.cuh>
Expand Down Expand Up @@ -50,24 +51,50 @@ void minClusterAndDistanceCompute(
raft::KeyValuePair<IndexT, DataT> initial_value(0, std::numeric_limits<DataT>::max());
raft::matrix::fill(handle, minClusterAndDistance, initial_value);

workspace.resize((sizeof(int)) * n_samples, stream);

cuvs::distance::fusedDistanceNNMinReduce<DataT, raft::KeyValuePair<IndexT, DataT>, IndexT>(
minClusterAndDistance.data_handle(),
X.data_handle(),
centroids.data_handle(),
L2NormX.data_handle(),
centroidsNorm.data_handle(),
n_samples,
n_clusters,
n_features,
(void*)workspace.data(),
metric != cuvs::distance::DistanceType::L2Expanded,
false,
true,
metric,
0.0f,
stream);
bool should_use_fused =
use_fused<DataT, IndexT, IndexT>(handle, n_samples, n_clusters, n_features);

if (should_use_fused) {
workspace.resize((sizeof(int)) * n_samples, stream);

cuvs::distance::fusedDistanceNNMinReduce<DataT, raft::KeyValuePair<IndexT, DataT>, IndexT>(
minClusterAndDistance.data_handle(),
X.data_handle(),
centroids.data_handle(),
L2NormX.data_handle(),
centroidsNorm.data_handle(),
n_samples,
n_clusters,
n_features,
(void*)workspace.data(),
metric != cuvs::distance::DistanceType::L2Expanded,
false,
true,
metric,
0.0f,
stream);
} else {
workspace.resize(sizeof(DataT) * n_samples * n_clusters, stream);

cuvs::distance::
unfusedDistanceNNMinReduce<DataT, DataT, raft::KeyValuePair<IndexT, DataT>, IndexT>(
handle,
minClusterAndDistance.data_handle(),
X.data_handle(),
centroids.data_handle(),
L2NormX.data_handle(),
centroidsNorm.data_handle(),
n_samples,
n_clusters,
n_features,
(void*)workspace.data(),
metric != cuvs::distance::DistanceType::L2Expanded,
false,
true,
metric,
0.0f,
stream);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
} else {
auto dataBatchSize = getDataBatchSize(batch_samples, n_samples);
auto centroidsBatchSize = getCentroidsBatchSize(batch_centroids, n_clusters);
Expand Down
Loading
Loading