Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sorting 在CUDA中对许多小数组进行排序_Sorting_Cuda_Cub - Fatal编程技术网

Sorting 在CUDA中对许多小数组进行排序

Sorting 在CUDA中对许多小数组进行排序,sorting,cuda,cub,Sorting,Cuda,Cub,我正在CUDA中实现中值滤波器。对于一个特定的像素,我提取了与像素周围的一个窗口对应的邻域,比如一个nxn(3x3)窗口,现在有了一个nxn元素数组。我不打算为我的应用程序使用超过10x10元素的窗口 这个数组现在本地存在于内核中,并且已经加载到设备内存中。从我之前读过的SO文章中,最常见的排序算法是通过推力实现的。但是,推力只能从主机调用。螺纹- 有没有一种快速有效的方法来对内核中的nxn元素数组进行排序?如果您使用的是CUDA 5.x,那么可以使用动态并行。您可以在过滤器内核中创建一些子内核

我正在CUDA中实现中值滤波器。对于一个特定的像素,我提取了与像素周围的一个窗口对应的邻域,比如一个
nxn
3x3
)窗口,现在有了一个
nxn
元素数组。我不打算为我的应用程序使用超过
10x10
元素的窗口

这个数组现在本地存在于内核中,并且已经加载到设备内存中。从我之前读过的SO文章中,最常见的排序算法是通过推力实现的。但是,推力只能从主机调用。螺纹-


有没有一种快速有效的方法来对内核中的
nxn
元素数组进行排序?

如果您使用的是CUDA 5.x,那么可以使用动态并行。您可以在过滤器内核中创建一些子内核来完成排序工作。至于如何按CUDA排序,您可以使用一些归纳技巧。

如果元素数量固定且较小,您可以使用排序网络()。它为固定数量的元素提供固定数量的比较/交换操作(例如,8个元素的19次比较/交换迭代)。

您的问题是在CUDA中对许多小数组进行排序

根据罗伯特在评论中的建议,他提出了一个可能的解决方案来面对这个问题。下面我将报告一个围绕Robert的代码构建的示例

其思想是将要排序的小数组分配给不同的线程块,然后使用对每个数组进行排序。提供了两种版本,一种是加载,另一种是将小阵列加载到共享内存中

最后让我注意到,您关于CUDA推力不能从内核内部调用的说法不再正确。您链接到的帖子已更新为其他答案

#include <cub/cub.cuh>
#include <stdio.h>
#include <stdlib.h>

#include "Utilities.cuh"

using namespace cub;

/**********************************/
/* CUB BLOCKSORT KERNEL NO SHARED */
/**********************************/
template <int BLOCK_THREADS, int ITEMS_PER_THREAD>
__global__ void BlockSortKernel(int *d_in, int *d_out)
{
    // --- Specialize BlockLoad, BlockStore, and BlockRadixSort collective types
    typedef cub::BlockLoad      <int*, BLOCK_THREADS, ITEMS_PER_THREAD, BLOCK_LOAD_TRANSPOSE>   BlockLoadT;
    typedef cub::BlockStore     <int*, BLOCK_THREADS, ITEMS_PER_THREAD, BLOCK_STORE_TRANSPOSE>  BlockStoreT;
    typedef cub::BlockRadixSort <int , BLOCK_THREADS, ITEMS_PER_THREAD>                         BlockRadixSortT;

    // --- Allocate type-safe, repurposable shared memory for collectives
    __shared__ union {
        typename BlockLoadT     ::TempStorage load;
        typename BlockStoreT    ::TempStorage store;
        typename BlockRadixSortT::TempStorage sort;
    } temp_storage;

    // --- Obtain this block's segment of consecutive keys (blocked across threads)
    int thread_keys[ITEMS_PER_THREAD];
    int block_offset = blockIdx.x * (BLOCK_THREADS * ITEMS_PER_THREAD);

    BlockLoadT(temp_storage.load).Load(d_in + block_offset, thread_keys);
    __syncthreads(); 

    // --- Collectively sort the keys
    BlockRadixSortT(temp_storage.sort).Sort(thread_keys);
    __syncthreads(); 

    // --- Store the sorted segment
    BlockStoreT(temp_storage.store).Store(d_out + block_offset, thread_keys);

}

/*******************************/
/* CUB BLOCKSORT KERNEL SHARED */
/*******************************/
template <int BLOCK_THREADS, int ITEMS_PER_THREAD>
__global__ void shared_BlockSortKernel(int *d_in, int *d_out)
{
    // --- Shared memory allocation
    __shared__ int sharedMemoryArray[BLOCK_THREADS * ITEMS_PER_THREAD];

    // --- Specialize BlockStore and BlockRadixSort collective types
    typedef cub::BlockRadixSort <int , BLOCK_THREADS, ITEMS_PER_THREAD> BlockRadixSortT;

    // --- Allocate type-safe, repurposable shared memory for collectives
    __shared__ typename BlockRadixSortT::TempStorage temp_storage;

    int block_offset = blockIdx.x * (BLOCK_THREADS * ITEMS_PER_THREAD);

    // --- Load data to shared memory
    for (int k = 0; k < ITEMS_PER_THREAD; k++) sharedMemoryArray[threadIdx.x * ITEMS_PER_THREAD + k]  = d_in[block_offset + threadIdx.x * ITEMS_PER_THREAD + k];
    __syncthreads();

    // --- Collectively sort the keys
    BlockRadixSortT(temp_storage).Sort(*static_cast<int(*)[ITEMS_PER_THREAD]>(static_cast<void*>(sharedMemoryArray + (threadIdx.x * ITEMS_PER_THREAD))));
    __syncthreads();

    // --- Write data to shared memory
    for (int k = 0; k < ITEMS_PER_THREAD; k++) d_out[block_offset + threadIdx.x * ITEMS_PER_THREAD + k] = sharedMemoryArray[threadIdx.x * ITEMS_PER_THREAD + k];

}

/********/
/* MAIN */
/********/
int main() {

    const int numElemsPerArray  = 8;
    const int numArrays         = 4;
    const int N                 = numArrays * numElemsPerArray;
    const int numElemsPerThread = 4;

    const int RANGE             = N * numElemsPerThread;

    // --- Allocating and initializing the data on the host
    int *h_data = (int *)malloc(N * sizeof(int));
    for (int i = 0 ; i < N; i++) h_data[i] = rand() % RANGE;

    // --- Allocating the results on the host
    int *h_result1 = (int *)malloc(N * sizeof(int));
    int *h_result2 = (int *)malloc(N * sizeof(int));

    // --- Allocating space for data and results on device
    int *d_in;      gpuErrchk(cudaMalloc((void **)&d_in,   N * sizeof(int)));
    int *d_out1;    gpuErrchk(cudaMalloc((void **)&d_out1, N * sizeof(int)));
    int *d_out2;    gpuErrchk(cudaMalloc((void **)&d_out2, N * sizeof(int)));

    // --- BlockSortKernel no shared
    gpuErrchk(cudaMemcpy(d_in, h_data, N*sizeof(int), cudaMemcpyHostToDevice));
    BlockSortKernel<N / numArrays / numElemsPerThread, numElemsPerThread><<<numArrays, numElemsPerArray / numElemsPerThread>>>(d_in, d_out1); 
    gpuErrchk(cudaMemcpy(h_result1, d_out1, N*sizeof(int), cudaMemcpyDeviceToHost));

    printf("BlockSortKernel no shared\n\n");
    for (int k = 0; k < numArrays; k++) 
        for (int i = 0; i < numElemsPerArray; i++)
            printf("Array nr. %i; Element nr. %i; Value %i\n", k, i, h_result1[k * numElemsPerArray + i]);

    // --- BlockSortKernel with shared
    gpuErrchk(cudaMemcpy(d_in, h_data, N*sizeof(int), cudaMemcpyHostToDevice));
    shared_BlockSortKernel<N / numArrays / numElemsPerThread, numElemsPerThread><<<numArrays, numElemsPerArray / numElemsPerThread>>>(d_in, d_out2); 
    gpuErrchk(cudaMemcpy(h_result2, d_out2, N*sizeof(int), cudaMemcpyDeviceToHost));

    printf("\n\nBlockSortKernel with shared\n\n");
    for (int k = 0; k < numArrays; k++) 
        for (int i = 0; i < numElemsPerArray; i++)
            printf("Array nr. %i; Element nr. %i; Value %i\n", k, i, h_result2[k * numElemsPerArray + i]);

    return 0;
}
#包括
#包括
#包括
#包括“Utilities.cuh”
使用名称空间cub;
/**********************************/
/*CUB BLOCKSORT内核没有共享*/
/**********************************/
模板
__全局无效BlockSortKernel(int*d\u输入,int*d\u输出)
{
//---专门化BlockLoad、BlockStore和BlockRadixSort集合类型
typedef cub::BlockLoad BlockLoadT;
typedef cub::BlockStore BlockStoreT;
typedef cub::BlockRadixSort BlockRadixSort;
//---为集体分配类型安全、可重复利用的共享内存
__共享联合{
typename BlockLoadT::TempStorage load;
typename BlockStoreT::TempStorage store;
typename BlockRadixSortT::TempStorage排序;
}临时储存;
//---获取此块的连续键段(跨线程阻塞)
int thread_key[每个线程的项目数];
int block_offset=blockIdx.x*(块线程*每个线程的项目);
BlockLoadT(temp_storage.load).load(数据输入+块偏移,线程键);
__同步线程();
//---对键进行集体排序
BlockRadixSortT(temp_storage.sort).sort(thread_键);
__同步线程();
//---存储已排序的段
块存储(temp_storage.store)。存储(d_out+块偏移,线程键);
}
/*******************************/
/*CUB块排序内核共享*/
/*******************************/
模板
__全局无效共享块内核(int*d\u输入,int*d\u输出)
{
//---共享内存分配
__shared_uuuint sharedMemoryArray[阻止线程*每个线程的项目];
//---专门化BlockStore和BlockRadixSort集合类型
typedef cub::BlockRadixSort BlockRadixSort;
//---为集体分配类型安全、可重复利用的共享内存
__共享类型名BlockRadixSortT::临时存储临时存储;
int block_offset=blockIdx.x*(块线程*每个线程的项目);
//---将数据加载到共享内存
对于(int k=0;k