尽管我了解本文中描述的并行归约背后的逻辑,但对于输入数组为 1 的简单示例,我似乎无法运行它size
。
这是我到目前为止所取得的成就。请记住,我正在使用推力库来管理输入和输出数据。
#include <iostream>
#include <thrust/host_vector.h>
#include <thrust/device_vector.h>
#include <thrust/sort.h>
#include <ctime>
#include <sys/time.h>
#include <sstream>
#include <string>
#include <fstream>
using namespace std;
__global__ void reduce0(int *g_idata, int *g_odata){
extern __shared__ int sdata[];
unsigned int tid = threadIdx.x;
unsigned int i = blockIdx.x*blockDim.x + threadIdx.x;
sdata[tid] = g_idata[i];
__syncthreads();
for(unsigned int s=1; s < blockDim.x; s *= 2) {
if (tid % (2*s) == 0) {
sdata[tid] += sdata[tid + s];
}
__syncthreads();
}
if (tid == 0) g_odata[blockIdx.x] = sdata[0];
}
int main(void){
int size = 10;
thrust::host_vector<int> data_h_i(size, 1);
//initialize the data, all values will be 1
//so the final sum will be equal to 10
int threadsPerBlock = 256;
int totalBlocks = size/threadsPerBlock + 1;
dim3 dimGrid(totalBlocks,1,1);
dim3 dimBlock(threadsPerBlock, 1, 1);
thrust::device_vector<int> data_v_i = data_h_i;
thrust::device_vector<int> data_v_o(size);
int* output = thrust::raw_pointer_cast(data_v_o.data());
int* input = thrust::raw_pointer_cast(data_v_i.data());
reduce0<<<dimGrid, dimBlock>>>(input, output);
data_v_i.clear();
data_v_i.shrink_to_fit();
thrust::host_vector<int> data_h_o = data_v_o;
data_v_o.clear();
data_v_o.shrink_to_fit();
cout<<data_h_o[0]<<endl;
return 0;
}
代码很简单,我创建一个host_vector
大小size
并将所有值初始化为 1。
然后我说我们每个块需要 256 个线程,并动态找到我的示例所需的块数量。
为了简单起见,我只创建了一个包含 10 个值的数组,这意味着我们只需要一个块。因此,一次内核调用就足以产生最终结果。
我的问题如下:
问题 1
编译上述示例 ( nvcc -O3 reduction.cu -arch=sm_21
) 并输入后,./a.out
我收到以下消息:
terminate called after throwing an instance of 'thrust::system::system_error'
what(): unspecified launch failure
我不确定这里发生了什么,但在我看来,错误来自这条线
sdata[tid] = g_idata[i]
内核是论文中描述的内核的精确副本,因此我不确定需要进行哪些更改才能解决此问题。
问题2
如果我们解决第一个问题,我们如何才能使上述代码适用于任意大小的输入数组?例如,如果我们size
的块数超过 256,那么我们至少需要两个块,因此每个块将给出一个输出,然后必须将其与其他块的输出组合。在论文中它说我们需要多次调用内核,但是我不确定如何动态完成。
先感谢您
EDIT1:对于问题 1,我似乎没有为共享内存正确分配内存。像这样调用内核:reduce0<<<dimGrid, dimBlock, size*sizeof(int)>>>(input, output);
并检查是否tid
超出范围。使代码正常工作。新内核如下:
__global__ void reduce0(int *g_idata, int *g_odata, int size){
extern __shared__ int sdata[];
unsigned int tid = threadIdx.x;
unsigned int i = blockIdx.x*blockDim.x + threadIdx.x;
if(tid<size){
sdata[tid] = g_idata[i];
__syncthreads();
for(unsigned int s=1; s < size; s *= 2) {
if (tid % (2*s) == 0) {
sdata[tid] += sdata[tid + s];
}
__syncthreads();
}
if (tid == 0) g_odata[blockIdx.x] = sdata[0];
}
}
不过,我仍然不确定问题 2。