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
10 changes: 6 additions & 4 deletions nsparse/cluster/inverted_list_clusters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,14 +125,16 @@ SparseVectors summarize_with_cpu_(const SparseVectors* vectors,

#ifdef NSPARSE_WITH_GPU
// GPU per-term max-pool: one kernel launch for the whole list, then the shared
// CPU sort/truncate. float (U32) only. Returns std::nullopt when the GPU
// declines (unavailable / empty list) so the caller falls back to the CPU path.
// CPU sort/truncate. float (U32) and 8-bit (uint8_t) only; a 0..255 code max is
// exact in the float summary value. Returns std::nullopt when the GPU declines
// (unavailable / empty list) or T is unsupported (e.g. uint16_t) so the caller
// falls back to the CPU path.
template <class T>
std::optional<SparseVectors> summarize_with_gpu_(
const SparseVectors* vectors, std::span<const idx_t> group_of_doc_ids,
std::span<const idx_t> offsets, float alpha) {
if constexpr (!std::is_same_v<T, float>) {
return std::nullopt; // GPU max-pool is float-only
if constexpr (!std::is_same_v<T, float> && !std::is_same_v<T, uint8_t>) {
return std::nullopt; // GPU max-pool supports only float and 8-bit
} else {
const size_t n_clusters = offsets.size() - 1;
std::vector<detail::GpuSummarizer::ClusterSummary> gpu_clusters;
Expand Down
13 changes: 8 additions & 5 deletions nsparse/cluster/kmeans_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,11 +169,14 @@ void map_docs_to_clusters(const SparseVectors* vectors,
return;
}
#ifdef NSPARSE_WITH_GPU
// GPU assignment (cuSPARSE) for float (U32) weights. It matches the CPU
// path below (skips centroids, ties to the lowest cluster index); on any
// failure we fall through to CPU. No AVX-512 exclusion is needed: there is
// now a single CPU path and it skips centroids like the GPU one.
if (vectors->get_element_size() == U32 &&
// GPU assignment (cuSPARSE) for float (U32) or 8-bit (U8) weights. It
// matches the CPU path below (skips centroids, ties to the lowest cluster
// index); on any failure we fall through to CPU. 8-bit uses int32
// accumulation on the GPU, which is exact for byte-sized products and so
// yields the same argmax as the CPU int64 path. 16-bit (U16) is not
// offloaded: its products need int64, which the GPU path does not do.
const auto gpu_element_size = vectors->get_element_size();
if ((gpu_element_size == U32 || gpu_element_size == U8) &&
should_offload_assignment_to_gpu(docs.size(), clusters.size())) {
try {
GpuClusterAssigner::instance().assign(vectors, docs, clusters);
Expand Down
Loading
Loading