在计算两个数组的点积时,我只是在寻求一些帮助。
我想说我将数组大小设置为2500,每个块的最大线程数设置为1024.
本质上,我想计算每个块的点积,然后在另一个核函数中求和点积。我计算了这样的块数:
nblcks = (n + 1024 -1)/1024
所以,nblcks = 3
这是我的核心功能:
// calculate the dot product block by block
__global__ void dotProduct(const float* a, const float* b, float* c, int n){
// store the product of a[i] and b[i] in shared memory
// sum the products in shared memory
// store the sum in c[blockIdx.x]
__shared__ float s[ntpb];
int tIdx = threadIdx.x;
int i = blockDim.x * blockIdx.x + threadIdx.x;
//calc product
if (i < n)
s[tIdx] = a[i] * b[i];
__syncthreads();
for (int stride = 1; stride < blockDim.x; stride <<= 1) {
if (tIdx % (2 * stride) == 0)
s[tIdx] += s[tIdx + stride];
__syncthreads();
}
if (threadIdx.x == 0){
c[blockIdx.x] = s[0];
}
}
我打电话给内核:
dotProduct<<<nblocks, ntpb>>>(d_a, d_b, d_c, n);
一切正常!好吧,差不多。
d_c,它有3个元素 - 每个元素都是块的点积在最后一个元素上抛出。
d_c[0] = correct
d_c[1] = correct
d_c[2] = some massive number of 10^18
有人能指出为什么会这样吗?它似乎只适用于1024的倍数。所以... 2048,3072等...我是否迭代空值或堆栈溢出?
谢谢!
编辑:
// host vectors
float* h_a = new float[n];
float* h_b = new float[n];
init(h_a, n);
init(h_b, n);
// device vectors (d_a, d_b, d_c)
float* d_a;
float* d_b;
float* d_c;
cudaMalloc((void**)&d_a, n * sizeof(float));
cudaMalloc((void**)&d_b, n * sizeof(float));
cudaMalloc((void**)&d_c, nblocks * sizeof(float));
// copy from host to device h_a -> d_a, h_b -> d_b
cudaMemcpy(d_a, h_a, n * sizeof(float), cudaMemcpyHostToDevice);
cudaMemcpy(d_b, h_b, n * sizeof(float), cudaMemcpyHostToDevice);
数组的初始化在此函数中完成(n次):
void init(float* a, int n) {
float f = 1.0f / RAND_MAX;
for (int i = 0; i < n; i++)
a[i] = std::rand() * f; // [0.0f 1.0f]
}
答案 0 :(得分:2)
这里的基本问题是,当每个块具有两个线程的舍入功率时,总和减少只能正常工作,共享内存中的每个条目都被初始化。如果您执行以下操作,那么这不是实践中的限制:
__global__ void dotProduct(const float* a, const float* b, float* c, int n){
// store the product of a[i] and b[i] in shared memory
// sum the products in shared memory
// store the sum in c[blockIdx.x]
__shared__ float s[ntpb];
int tIdx = threadIdx.x;
int i = blockDim.x * blockIdx.x + threadIdx.x;
//calc product
s[tIdx] = 0.f;
while (i < n) {
s[tIdx] += a[i] * b[i];
i += blockDim.x * gridDim.x;
}
__syncthreads();
for (int stride = 1; stride < blockDim.x; stride <<= 1) {
if (tIdx % (2 * stride) == 0)
s[tIdx] += s[tIdx + stride];
__syncthreads();
}
if (threadIdx.x == 0){
c[blockIdx.x] = s[0];
}
}
并且每块运行两个线程的功率(即32,64,128,256,512或1024)。 while循环累积多个值并将该部分点积存储在共享内存中,每个条目包含0或有效的部分和,然后减少正常发生。不是运行与数据大小相同的块,而是运行尽可能多的同时“填充”您的GPU(或者如果问题大小很小,则比您认为的要少一个)。在较大的问题规模下,性能也将得到改善。
如果您还没有看过它,here is a very instructive whitepaper由NVIDIA的Mark Harris编写,逐步优化基本的并行缩减。我强烈建议你阅读它。