以下是我内核中行为不正常的部分,然后解释了我在调试时发现的内容。
__global__ void Mangler(float *matrix, int *map)
{
__shared__ signed int localMap[N];
if(0 == threadIdx.x)
{
for(int i=0; i<N; i++)
localMap[i] = -1;
}
__syncthreads();
int fn = ...; // a lot of code goes into this number, skipped for clarity
int rnumber = threadIdx.x;
int X = atomicCAS(&localMap[fn], -1, rnumber); // Spot of bother 1
if(X == -1) // Spot of bother 2
{
// some code
}
else
{
// other code
}
}
我在文档中发现atomicCAS(*address, compare, value)
基本上返回(并保存到给定地址)(old == compare ? value : old)
的结果,其中old是执行函数前地址的值。
对此,我认为执行int X = atomicCAS(&localMap[fn], -1, rnumber);
应该有两种可能的结果(根据NVidia Cuda C编程指南):
localMap[fn] == -1
,则X
的值应为rnumber
,localMap[fn]
的值应为rnumber
。 这不会发生。 localMap[fn] != -1
,那么X
应设置为localMap[fn]
的值,并且该值应保持不变。相反,正如使用NSight进行的调试所显示的那样,X
被分配为-1,而localMap[fn]
被赋予rnumber
的值。我不明白,但正如您在我的代码中所看到的,我已经更改了if
来捕捉这种情况。
这让我想到了第二个问题:尽管NSight将X
的值显示为-1,但if {}
被完全跳过(在任何命中都没有断点)并且执行直接跳转到else
。
我的问题:
atomicCAS
?if
的原因和else
哪些应该评估为真?我在Windows 8上使用NVidia CUDA 5.5,Visual Studio 2012 x64,NVidia Nsight Monitor Visual Studio Edition 3.1。该机器的GPU是NVidia GeForce GTX 550 Ti。
我尝试将语法更改为if(X!=-1)
; if的真正分支仍未执行。
答案 0 :(得分:1)
从文档中,atomicCAS
返回旧值,这意味着,在您的列表中,您的两个结果是错误的。您的X
将始终设置为localMap[fn]
的旧值,无论它具有哪个值。根据与-1的比较设置的是localMap[fn]
的新值。当它为-1时,它被设置为rnumber
,否则它将保持不变。
因此,您使用X
,rnumber
和localMap
的值看到的行为符合预期。
我无法解决你的第二个问题,因为我没有使用NSight,也不知道它是如何工作的 - 根据你的代码,你的真正分支应该被评估(但要小心:你的假分支也是 - 因为它是多线程的有些线程可以将条件评估为true,有些则为false - 我的猜测/假设是你必须以某种方式告诉你的调试器你要调试哪个线程/ warp / block并且你看错了。