Skip to content
Closed
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
22 changes: 20 additions & 2 deletions ggml/src/ggml-cuda/top-k.cu
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,13 @@ using namespace cub;
# endif // CCCL_MAJOR_VERSION >= 3 && CCCL_MINOR_VERSION >= 2
#endif // GGML_CUDA_USE_CUB

// Exact radix top-k selection when CUB DeviceTopK is unavailable:
// O(nrows) temp instead of the O(ncols*nrows) full-argsort fallback. Selects the same set.
// Set on CUDA without a new-enough CUB, or on HIP without CUB at all.
#if !defined(CUB_TOP_K_AVAILABLE) || (!defined(GGML_CUDA_USE_CUB) && defined(GGML_USE_HIP))
#define GGML_CUDA_USE_TOP_K_RADIX
#endif

#ifdef CUB_TOP_K_AVAILABLE

static void top_k_cub(ggml_cuda_pool & pool,
Expand All @@ -36,7 +43,7 @@ static void top_k_cub(ggml_cuda_pool & pool,
ncols, k, env));
}

#elif defined(GGML_CUDA_USE_CUB) // CUB_TOP_K_AVAILABLE
#elif defined(GGML_CUDA_USE_CUB) && !defined(GGML_CUDA_USE_TOP_K_RADIX) // CUB_TOP_K_AVAILABLE

static int next_power_of_2(int x) {
int n = 1;
Expand All @@ -48,7 +55,7 @@ static int next_power_of_2(int x) {

#endif // CUB_TOP_K_AVAILABLE

#if !defined(GGML_CUDA_USE_CUB) && defined(GGML_USE_HIP)
#if defined(GGML_CUDA_USE_TOP_K_RADIX)

static __device__ __forceinline__ uint32_t top_k_float_to_ordered(float value) {
const uint32_t bits = __float_as_uint(value);
Expand Down Expand Up @@ -232,6 +239,17 @@ void ggml_cuda_op_top_k(ggml_backend_cuda_context & ctx, ggml_tensor * dst) {
for (int i = 0; i < nrows; i++) {
top_k_cub(pool, src0_d + i * ncols, dst_d + i * k, ncols, k, stream);
}
#elif defined(GGML_CUDA_USE_TOP_K_RADIX)
// exact radix selection: ~nrows*blocks*256 ints of temp (MBs, not 100s of MBs)
if (ncols > 1024) {
top_k_radix_cuda(pool, src0_d, dst_d, (int) ncols, (int) nrows, (int) k, stream);
} else {
ggml_cuda_pool_alloc<int> temp_dst_alloc(pool, ncols * nrows);
int * tmp_dst = temp_dst_alloc.get();
argsort_f32_i32_cuda_bitonic(src0_d, tmp_dst, ncols, nrows, GGML_SORT_ORDER_DESC, stream);
CUDA_CHECK(cudaMemcpy2DAsync(dst_d, k * sizeof(int), tmp_dst, ncols * sizeof(int), k * sizeof(int), nrows,
cudaMemcpyDeviceToDevice, stream));
}
#elif defined(GGML_CUDA_USE_CUB) // CUB_TOP_K_AVAILABLE
// Fall back to argsort + copy
const int ncols_pad = next_power_of_2(ncols);
Expand Down