Cuda 相对较小阵列尺寸的GPU精度问题?
我有一些CUDA代码,它做了一些线性代数来反转一种特殊类型的结构化矩阵。我使用该算法的序列化版本的结果计算RMS错误。错误会随着问题的大小而增长,达到我预期的更大程度。有人能解释为什么会出现这种情况吗 GPU代码非常幼稚。这是有意的,我会很快优化它-我只是想要一个简单的基线内核,提供适当的结果Cuda 相对较小阵列尺寸的GPU精度问题?,cuda,precision,Cuda,Precision,我有一些CUDA代码,它做了一些线性代数来反转一种特殊类型的结构化矩阵。我使用该算法的序列化版本的结果计算RMS错误。错误会随着问题的大小而增长,达到我预期的更大程度。有人能解释为什么会出现这种情况吗 GPU代码非常幼稚。这是有意的,我会很快优化它-我只是想要一个简单的基线内核,提供适当的结果 __global__ void levinson_durbin_gpu(TYPE *h0_d, TYPE *h_d, TYPE *v_d, TYPE *x_d, TYPE *y_d, int N) //
__global__ void levinson_durbin_gpu(TYPE *h0_d, TYPE *h_d, TYPE *v_d, TYPE *x_d, TYPE *y_d, int N) //Naive kernel
{
int j = threadIdx.x;
int i;
__shared__ TYPE hn_1[512];
hn_1[j] = h_d[j];
for(i=1; i<N; i++)
{
if(j < i)
{
TYPE hn = h_d[i];
TYPE yn = y_d[i];
__syncthreads();
//Set up temporary arrays, compute inner products
__shared__ TYPE temp[512]; //Temp for hn_1_J_v
__shared__ TYPE temp2[512]; //Temp for hn_1_J_x
__shared__ TYPE temp3[512]; //Temp for hn_1_v
temp[j] = hn_1[j]*v_d[i-j-1];
temp2[j] = hn_1[j]*x_d[i-j-1];
temp3[j] = hn_1[j]*v_d[j];
__syncthreads();
//Three reductions at once
for(unsigned int s=1; s<i; s*=2)
{
int index = 2*s*j;
if((index+s) < i)
{
temp[index] += temp[index+s];
temp2[index] += temp2[index+s];
temp3[index] += temp3[index+s];
}
__syncthreads();
}
TYPE hn_1_J_v = temp[0];
TYPE hn_1_J_x = temp2[0];
TYPE hn_1_v = temp3[0];
TYPE alpha_v = (hn - hn_1_J_v)/(h0_d[0] - hn_1_v);
TYPE alpha_x = (yn - hn_1_J_x)/(h0_d[0] - hn_1_v);
__shared__ TYPE w_v[512];
w_v[j] = v_d[j] - alpha_v*v_d[i-j-1];
__shared__ TYPE w_x[512];
w_x[j] = x_d[j] - alpha_x*v_d[i-j-1];
v_d[j] = w_v[j];
x_d[j] = w_x[j];
if(j == 0)
{
v_d[i] = alpha_v;
x_d[i] = alpha_x;
}
}
__syncthreads();
}
}
\uuuuu global\uuuuu void levinson\u durbin\u gpu(类型*h0\u d,类型*h\u d,类型*v\u d,类型*x\u d,类型*y\u d,int N)//朴素内核
{
int j=螺纹IDX.x;
int i;
__共享_uuu类型hn_u1[512];
hn_1[j]=h_d[j];
因为(i=1;i多亏了评论部分的帮助,我才能够自己解决这个问题,所以我将在这里记录下来,以防其他人遇到类似的问题
问题确实是同步问题-我在发散控制流块中使用了\uu syncthreads()
。解决方案是将该控制流块分成多个部分,并在每个部分后调用\uu syncthreads()
:
__global__ void levinson_durbin_gpu(TYPE *h0_d, TYPE *h_d, TYPE *v_d, TYPE *x_d, TYPE *y_d, int N) //Naive kernel
{
int j = threadIdx.x;
int i;
__shared__ TYPE hn_1[512];
hn_1[j] = h_d[j];
__syncthreads();
//Set up temporary arrays
__shared__ TYPE temp[512]; //Temp for hn_1_J_v
__shared__ TYPE temp2[512]; //Temp for hn_1_J_x
__shared__ TYPE temp3[512]; //Temp for hn_1_v
TYPE hn;
TYPE yn;
for(i=1; i<N; i++)
{
if(j < i)
{
hn = h_d[i];
yn = y_d[i];
//Compute inner products
temp[j] = hn_1[j]*v_d[i-j-1];
temp2[j] = hn_1[j]*x_d[i-j-1];
temp3[j] = hn_1[j]*v_d[j];
}
__syncthreads();
//Have all threads complete this section to avoid synchronization issues
//Three reductions at once
for(unsigned int s=1; s<i; s*=2)
{
int index = 2*s*j;
if((index+s) < i)
{
temp[index] += temp[index+s];
temp2[index] += temp2[index+s];
temp3[index] += temp3[index+s];
}
__syncthreads();
}
if(j < i)
{
TYPE hn_1_J_v = temp[0];
TYPE hn_1_J_x = temp2[0];
TYPE hn_1_v = temp3[0];
TYPE alpha_v = (hn - hn_1_J_v)/(h0_d[0] - hn_1_v);
TYPE alpha_x = (yn - hn_1_J_x)/(h0_d[0] - hn_1_v);
__shared__ TYPE w_v[512];
w_v[j] = v_d[j] - alpha_v*v_d[i-j-1];
__shared__ TYPE w_x[512];
w_x[j] = x_d[j] - alpha_x*v_d[i-j-1];
v_d[j] = w_v[j];
x_d[j] = w_x[j];
if(j == 0)
{
v_d[i] = alpha_v;
x_d[i] = alpha_x;
}
}
__syncthreads();
}
}
\uuuuu global\uuuuu void levinson\u durbin\u gpu(类型*h0\u d,类型*h\u d,类型*v\u d,类型*x\u d,类型*y\u d,int N)//朴素内核
{
int j=螺纹IDX.x;
int i;
__共享_uuu类型hn_u1[512];
hn_1[j]=h_d[j];
__同步线程();
//设置临时数组
__共享的uuuuuuuuu类型临时[512];//hn_1_J_v的临时
__共享的uuu类型temp2[512];//hn_1_J_x的Temp
__共享的uuu类型temp3[512];//hn_1_v的Temp
hn型;
yn型;
对于(i=1;这可能与精度无关,而与缓冲区溢出有关。如果没有完整的复制案例来研究,很难猜测可能会出现什么问题,但我会非常怀疑index=2*s*j
。如果我正确地阅读了代码,对于你的N=80示例,你可以得到i=79,j=78 w这将给出s=64和index=2*64*78=9984,这是一个很大的缓冲区溢出。您确认没有API错误并尝试使用cuda memcheck运行代码了吗?感谢您的回复@talonmies。我已经确认没有API错误,但我还没有使用cuda memcheck,我很快就会这样做。只是想弄清楚,为什么这样的缓冲区会溢出流正在发生?请注意,我只在(index+s)
时访问临时数组,因此在您的示例中,我只通过temp[79]
访问temp[0]
,因为N=80
@Adam27X:调用syncthreads()时,条件分支“if(jI+1
取决于循环迭代I
的结果,所以我确实需要某种障碍。。。