我正在尝试编写一个CUDA内核,其中每个线程执行一个单独的迭代算法。有点像许多独立的Newton-Raphson解决方案。问题是经过一定次数的迭代后出现了问题。谷歌搜索表明它可能是一个分段错误,但我不知道如何纠正这一点。我写了一些再现错误的玩具代码:
#include <iostream>
#include <cuda_runtime.h>
#include <assert.h>
#define N 3
__device__ void devFunc(float4 *in, float4 *out){
out[0] = in[0];
//Placeholder useless computations
for (int i = 0; i < 1000; ++i){
out[0].w = out[0].w + 1.0;
out[0].x = out[0].w + 1.0;
out[0].y = out[0].w + 1.0;
out[0].z = out[0].w + 1.0;
out[0].w = out[0].w - 1.0;
out[0].x = out[0].w - 1.0;
out[0].y = out[0].w - 1.0;
out[0].z = out[0].w - 1.0;
}
out[0].w = 26.0;
out[0].x = 26.0;
out[0].y = 26.0;
out[0].z = 26.0;
}
__global__ void testKernel(float4 *vects){
const int i = blockIdx.x;
//Iterative algorithm, fails for 1000 iterations
for (int j = 0; j < 1000; ++j){
devFunc(&vects[i], &vects[i]);
}
}
int main(){
float4 vects[N];
//Preprare original data
for (int i = 0; i < N; ++i){
vects[i].w = 5.0;
vects[i].x = 5.0;
vects[i].y = 5.0;
vects[i].z = 5.0;
}
//Print original data
std::cout << "Original data:" << std::endl;
for (int i = 0; i < N; ++i){
std::cout << vects[i].w
<< "\t" << vects[i].x
<< "\t" << vects[i].y
<< "\t" << vects[i].z
<< "\t" << std::endl;
}
cudaError_t stat = cudaSuccess;
float4 *d_vects;
stat = cudaMalloc(&d_vects, sizeof(float4)*N);
assert(stat == cudaSuccess);
stat = cudaMemcpy(d_vects, vects, sizeof(float4)*N, cudaMemcpyHostToDevice);
assert(stat == cudaSuccess);
testKernel<<<N, 1>>>(d_vects);
stat = cudaMemcpy(vects, d_vects, sizeof(float4)*N, cudaMemcpyDeviceToHost);
assert(stat == cudaSuccess);
stat = cudaFree(d_vects);
assert(stat == cudaSuccess);
//Print processed data
std::cout << "Processed data:" << std::endl;
for (int i = 0; i < N; ++i){
std::cout << vects[i].w
<< "\t" << vects[i].x
<< "\t" << vects[i].y
<< "\t" << vects[i].z
<< "\t" << std::endl;
}
}
玩具代码以非常低效的方式将一些5的向量更改为26的向量,但更重要的是再现错误。因此,当我在__global__
内核中运行for循环1000次迭代时,会触发cudaMemcpy
d_vects
上的错误代码4返回主机。如果我将迭代降级到100,一切都会正常工作。我也尝试了上面代码的一个版本,其中__device__
函数接受并返回float4
而不是指针......同样的错误。
我的一个理论是,根据CUDA编程指南的大小和对齐要求,我的数据结构可能没有“自然对齐”:
“读取非自然对齐的8字节或16字节字会产生不正确的结果(关闭几个字),因此必须特别注意保持这些值的任何值或数组的起始地址对齐类型“。 see here
但这不是问题,因为我正在使用CUDA的float4
编程指南说满足要求。我的硬件计算能力是5.2。
所以我的问题是导致此错误的原因以及如何纠正?谢谢。
我尝试过的其他一些事情:
•调整执行配置<<<Dg, Db, Ns, S>>>
的第3个参数,即动态分配的共享内存中的字节数
注意上面“//Placeholder useless computations
”中的计算量会更改在发生memcpy错误之前可能执行的迭代次数,这也很有用。例如,如果我用更接近牛顿迭代的东西替换占位符,则仅在8次迭代后出现错误。
谢谢。