55
66#include " cuda_topk.h"
77#include " cuda_topk_full_sort.cuh"
8+ #include " cuda_topk_hybrid_sort.cuh"
89#include " cuda_topk_select_sort.cuh"
910
1011namespace Generators {
1112namespace cuda {
1213
14+ // Helper to determine the optimal partition size for the hybrid sort algorithm
15+ // based on vocabulary and batch size.
16+ inline int GetHybridSortPartitionSize (int vocab_size, int batch_size) {
17+ if (vocab_size >= 147456 ) {
18+ return (vocab_size > 256 * 1024 ) ? 8192 : 4096 ;
19+ } else {
20+ if (vocab_size >= 65536 || batch_size >= 4 && vocab_size > 49152 ) {
21+ return 2048 ;
22+ }
23+ }
24+
25+ return 1024 ;
26+ }
27+
1328TopkData::TopkData (int batch_size, int vocab_size, cudaStream_t stream) {
29+ // The intermediate buffers are used by hybrid and full sort algorithms.
30+ int partition_size = GetHybridSortPartitionSize (vocab_size, batch_size);
31+ size_t intermediate_buffer_elements = GetHybridSortIntermediateSize (batch_size, vocab_size, partition_size);
32+
1433 size_t vocab_batch_size = static_cast <size_t >(vocab_size) * batch_size;
1534
35+ // Selection sort uses a buffer of batch_size * 64 elements, which is smaller than intermediate_buffer_elements.
36+ size_t max_buffer_elements = std::max (vocab_batch_size, intermediate_buffer_elements);
37+
1638 // Allocate all necessary device memory
17- // The buffers are sized for the full sort algorithm, which is the largest.
18- intermediate_indices_1 = CudaMallocArray<int >(vocab_batch_size);
19- intermediate_indices_2 = CudaMallocArray<int >(vocab_batch_size);
20- intermediate_scores_1 = CudaMallocArray<float >(vocab_batch_size);
21- intermediate_scores_2 = CudaMallocArray<float >(vocab_batch_size);
39+ intermediate_indices_1 = CudaMallocArray<int >(max_buffer_elements);
40+ intermediate_indices_2 = CudaMallocArray<int >(max_buffer_elements);
41+ intermediate_scores_1 = CudaMallocArray<float >(max_buffer_elements);
42+ intermediate_scores_2 = CudaMallocArray<float >(max_buffer_elements);
2243 batch_offsets = CudaMallocArray<int >(batch_size + 1 );
2344
2445 cub_temp_storage_bytes = GetFullSortCubTempStorageBytes (vocab_batch_size, batch_size, stream);
2546 cub_temp_storage = CudaMallocArray<unsigned char >(this ->cub_temp_storage_bytes );
2647}
2748
28- // Kernel to compact strided data into a dense layout.
29- // Used to convert data from a [batch, stride] layout to a dense [batch, k] layout.
30- template <typename T>
31- __global__ void CompactStridedData (const T* input, T* output, int k, int batch_size, int input_stride) {
32- const int batch_idx = blockIdx .x ;
33- for (int i = threadIdx .x ; i < k; i += blockDim .x ) {
34- int in_idx = batch_idx * input_stride + i;
35- int out_idx = batch_idx * k + i;
36- output[out_idx] = input[in_idx];
37- }
38- }
39-
4049void TopkDataCompact::CompactOutput (int batch_size, int vocab_size, cudaStream_t stream, int k) {
4150 topk_scores_compact = CudaMallocArray<float >(static_cast <size_t >(batch_size) * k);
4251 topk_indices_compact = CudaMallocArray<int >(static_cast <size_t >(batch_size) * k);
@@ -50,12 +59,15 @@ void TopkDataCompact::CompactOutput(int batch_size, int vocab_size, cudaStream_t
5059void GetTopK (TopkData* topk_data, cudaStream_t stream, const float * scores_in, int vocab_size, int batch_size, int k) {
5160 assert (topk_data != nullptr );
5261
53- if (k > 64 ) {
62+ if (k > kHybridSortMaxK ) {
5463 LaunchSort (topk_data, stream, scores_in, topk_data->intermediate_scores_1 .get (),
5564 topk_data->intermediate_indices_1 .get (), vocab_size, batch_size);
56- } else {
65+ } else if (k <= 8 || vocab_size < 1024 ) {
5766 // NOTE: This modifies scores_in in-place
5867 RunTopKViaSelectionSort (topk_data, stream, const_cast <float *>(scores_in), vocab_size, batch_size, k);
68+ } else {
69+ int partition_size = GetHybridSortPartitionSize (vocab_size, batch_size);
70+ RunTopKViaHybridSort (topk_data, stream, scores_in, vocab_size, batch_size, k, partition_size);
5971 }
6072}
6173
0 commit comments