我想要运行cuda程序,但我是初学者。我必须为直方图编写一个程序。 但是用水桶。根据maxValue(示例中为40),该数字将添加到相应的存储桶中。如果我们有4个桶:
histo:| 1 | 10 | 30 | 39 | 32 | 2 | 4 | 5 | 1 |
0-9(第1桶)
10-19(第二桶)
20-29(第3桶)
30-39(第4桶)
我的GPU有计算能力1.1。
我试图为每个线程在临时表上添加其值的块的共享temp []做一些事情:
__global__ void histo_kernel_optimized5( unsigned char *buffer, long size,
unsigned int *histo )
{
extern __shared__ unsigned int temp[];
temp[threadIdx.x] = 0;
__syncthreads();
int i = threadIdx.x + blockIdx.x * blockDim.x;
int offset = blockDim.x * gridDim.x;
int bucketID;
while (i < size)
{
bucketID = array[i]/Bwidth;
atomicAdd( &temp[bucketID], 1);
i += offset;
}
__syncthreads();
atomicAdd( &(histo[threadIdx.x]), temp[threadIdx.x] );
}
histo_kernel_optimized <<<array_size/buckets, buckets,buckets*sizeof(unsigned int)>>>(buffer,SIZE, histogram)
但编译器sais: 指令'{atom,red} .shared'需要。目标sm_12或更高
我还尝试为每个创建的线程设置临时表:
__global__ void histo_kernel_optimized5( unsigned char *buffer, long size,
unsigned int *histo )
{
unsigned int temp[buckets];
int j;
for (j=0;j<buckets;j++){
temp[j]=0;
}
int bucketID;
int i = threadIdx.x + blockIdx.x * blockDim.x;
int offset = blockDim.x * gridDim.x;
while (i < size)
{
bucketID = array[i]/Bwidth;
temp[bucketID]++;
i += offset;
}
for (j=0;j<buckets;j++){
histo[j] += temp[j];
}
}
但编译器不允许我这样做,因为它需要一个常量来创建临时表。但问题是为命令行提供了桶动态。
还有其他办法吗?我不知道怎么做。我很困惑。
答案 0 :(得分:8)
使用原子时,启动较少的块将减少争用(从而提高性能),因为它不必在较少的块之间进行协调。启动更少的块,并使每个块循环遍历更多的输入元素。
for (unsigned tid = blockIdx.x*blockDim.x+threadIdx.x;
tid < size; tid += gridDim.x*blockDim.x) {
unsigned char value = array[tid]; // borrowing notation from another answer here
int bin = value % buckets;
atomicAdd(&histo[bin],1);
}
答案 1 :(得分:4)
直方图使用原子操作非常容易实现。我不知道你为什么写这么复杂的内核。并行化操作的动机是利用算法的并行性。无需迭代内核中的整个直方图。下面是一个示例CUDA内核和包装函数,用于计算具有指定bin数的数组的直方图。 我不认为它可以进一步优化Compute 1.1设备。但是对于Compute 1.2,可以使用共享内存。
__global__ void kernel_getHist(unsigned char* array, long size, unsigned int* histo, int buckets)
{
int tid = blockIdx.x * blockDim.x + threadIdx.x;
if(tid>=size) return;
unsigned char value = array[tid];
int bin = value % buckets;
atomicAdd(&histo[bin],1);
}
void getHist(unsigned char* array, long size, unsigned int* histo,int buckets)
{
unsigned char* dArray;
cudaMalloc(&dArray,size);
cudaMemcpy(dArray,array,size,cudaMemcpyHostToDevice);
unsigned int* dHist;
cudaMalloc(&dHist,buckets * sizeof(int));
cudaMemset(dHist,0,buckets * sizeof(int));
dim3 block(32);
dim3 grid((size + block.x - 1)/block.x);
kernel_getHist<<<grid,block>>>(dArray,size,dHist,buckets);
cudaMemcpy(histo,dHist,buckets * sizeof(int),cudaMemcpyDeviceToHost);
cudaFree(dArray);
cudaFree(dHist);
}
答案 2 :(得分:0)
对于没有原子操作的设备有一个解决方案,并显示了一种最小化片上内存冲突的方法,其中细分为Podlozhnyuk在Histogram calculation in CUDA
引起的扭曲代码位于CUDASamples \ 3_Imaging \ histogram(来自CUDA样本)