Cuda 完全在芯片上制作CUB blockradixsort?
我正在阅读CUB文档和示例:Cuda 完全在芯片上制作CUB blockradixsort?,cuda,gpu,radix-sort,cub,Cuda,Gpu,Radix Sort,Cub,我正在阅读CUB文档和示例: #include <cub/cub.cuh> // or equivalently <cub/block/block_radix_sort.cuh> __global__ void ExampleKernel(...) { // Specialize BlockRadixSort for 128 threads owning 4 integer items each typedef cub::BlockRadixSort<i
#include <cub/cub.cuh> // or equivalently <cub/block/block_radix_sort.cuh>
__global__ void ExampleKernel(...)
{
// Specialize BlockRadixSort for 128 threads owning 4 integer items each
typedef cub::BlockRadixSort<int, 128, 4> BlockRadixSort;
// Allocate shared memory for BlockRadixSort
__shared__ typename BlockRadixSort::TempStorage temp_storage;
// Obtain a segment of consecutive items that are blocked across threads
int thread_keys[4];
...
// Collectively sort the keys
BlockRadixSort(temp_storage).Sort(thread_keys);
...
}
#包括//或等效
__全局\uuuuvoid示例内核(…)
{
//为每个线程拥有4个整数项的128个线程专门化BlockRadixSort
typedef cub::BlockRadixSort BlockRadixSort;
//为BlockRadixSort分配共享内存
__共享类型名BlockRadixSort::TempStorage temp_storage;
//获取跨线程阻塞的连续项目段
int-thread_键[4];
...
//对键进行集体排序
BlockRadixSort(临时存储)。排序(线程键);
...
}
在本例中,每个线程有4个键。看起来“线程密钥”将在全局本地内存中分配。如果我每个线程只有一个键,我可以声明“int-thread\u-key;”并只在寄存器中设置这个变量吗
BlockRadixSort(temp_storage).Sort()将指向键的指针作为参数。这是否意味着密钥必须在全局内存中
我想使用此代码,但我希望每个线程在寄存器中保留一个键,并在排序后将其保留在寄存器/共享内存中的芯片上。
提前谢谢 您可以使用共享内存(将其保留在“芯片上”)来实现这一点。我不知道如何在不去构造
BlockRadixSort
对象的情况下使用严格的寄存器
下面是一个使用共享内存保存要排序的初始数据和最终排序结果的示例代码。此示例主要针对每个线程设置一个数据元素,因为这似乎是您所要求的。将其扩展到每个线程的多个元素并不困难,我已经将大部分管道安装到位,除了数据合成和调试打印输出:
#include <cub/cub.cuh>
#include <stdio.h>
#define nTPB 32
#define ELEMS_PER_THREAD 1
// Block-sorting CUDA kernel (nTPB threads each owning ELEMS_PER THREAD integers)
__global__ void BlockSortKernel()
{
__shared__ int my_val[nTPB*ELEMS_PER_THREAD];
using namespace cub;
// Specialize BlockRadixSort collective types
typedef BlockRadixSort<int, nTPB, ELEMS_PER_THREAD> my_block_sort;
// Allocate shared memory for collectives
__shared__ typename my_block_sort::TempStorage sort_temp_stg;
// need to extend synthetic data for ELEMS_PER_THREAD > 1
my_val[threadIdx.x*ELEMS_PER_THREAD] = (threadIdx.x + 5)%nTPB; // synth data
__syncthreads();
printf("thread %d data = %d\n", threadIdx.x, my_val[threadIdx.x*ELEMS_PER_THREAD]);
// Collectively sort the keys
my_block_sort(sort_temp_stg).Sort(*static_cast<int(*)[ELEMS_PER_THREAD]>(static_cast<void*>(my_val+(threadIdx.x*ELEMS_PER_THREAD))));
__syncthreads();
printf("thread %d sorted data = %d\n", threadIdx.x, my_val[threadIdx.x*ELEMS_PER_THREAD]);
}
int main(){
BlockSortKernel<<<1,nTPB>>>();
cudaDeviceSynchronize();
}
如果我有一个1024个线程块,但告诉BlockRadixSort TPB是512,会发生什么?它是否只使用前512个线程对数据进行排序?这不是代码的工作方式。这不是每个线程一个键,这是您的问题所指出的。
BlockRadixSort
的第二个自定义参数是“BLOCK_THREADS”,它是每个块的线程数。顺便问一下,有一个简单的问题:我们必须在这里使用两个“_syncthreads”吗?看起来排序函数只接受线程本身准备的值作为输入?我的想法是:排序基本上是在所有地方交换值。因此,是的,一个给定的线程可以“接收”它自己的输入值,但是一旦交换开始,所有的数据最好都是有效的。因此,第一次同步似乎是必要的,以便在任何交换开始之前,将所有合成数据填充并存储在共享mem中。现在,我将BlockRadixSort视为不透明。如果我查看它的内部,发现它做的第一件事是同步,那么显然我的第一次同步是多余的。第二次同步遵循类似的逻辑来保护后续代码。另外,作为另一个提示,您将注意到,已将BlockRadixSort括在\uuu syncthreads()
中。这对我来说意味着没有内部冗余的\uuu syncthreads()
,实际上它们是确保1所必需的。数据在交换开始前填充,以及2。交换在使用结果之前完成。
__device__ __forceinline__ void Sort(
Key (&keys)[ITEMS_PER_THREAD],
int begin_bit = 0,
int end_bit = sizeof(Key) * 8)
{ ...