55
66#include " cuda_topk.h"
77#include " cuda_topk_full_sort.cuh"
8- #include " cuda_topk_hybrid_sort.cuh"
98#include " cuda_topk_select_sort.cuh"
109
1110namespace Generators {
1211namespace cuda {
1312
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-
2813TopkData::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-
3314 size_t vocab_batch_size = static_cast <size_t >(vocab_size) * batch_size;
3415
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-
3816 // Allocate all necessary device memory
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);
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);
4322 batch_offsets = CudaMallocArray<int >(batch_size + 1 );
4423
4524 cub_temp_storage_bytes = GetFullSortCubTempStorageBytes (vocab_batch_size, batch_size, stream);
4625 cub_temp_storage = CudaMallocArray<unsigned char >(this ->cub_temp_storage_bytes );
4726}
4827
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+
4940void TopkDataCompact::CompactOutput (int batch_size, int vocab_size, cudaStream_t stream, int k) {
5041 topk_scores_compact = CudaMallocArray<float >(static_cast <size_t >(batch_size) * k);
5142 topk_indices_compact = CudaMallocArray<int >(static_cast <size_t >(batch_size) * k);
@@ -59,15 +50,12 @@ void TopkDataCompact::CompactOutput(int batch_size, int vocab_size, cudaStream_t
5950void GetTopK (TopkData* topk_data, cudaStream_t stream, const float * scores_in, int vocab_size, int batch_size, int k) {
6051 assert (topk_data != nullptr );
6152
62- if (k > kHybridSortMaxK ) {
53+ if (k > 64 ) {
6354 LaunchSort (topk_data, stream, scores_in, topk_data->intermediate_scores_1 .get (),
6455 topk_data->intermediate_indices_1 .get (), vocab_size, batch_size);
65- } else if (k <= 8 || vocab_size < 1024 ) {
56+ } else {
6657 // NOTE: This modifies scores_in in-place
6758 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);
7159 }
7260}
7361
0 commit comments