Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ms-access/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Cuda 为什么额外的\uuuSyncThreads()调用会导致意外行为?_Cuda - Fatal编程技术网

Cuda 为什么额外的\uuuSyncThreads()调用会导致意外行为?

Cuda 为什么额外的\uuuSyncThreads()调用会导致意外行为?,cuda,Cuda,我在CUDA示例中使用了改编自ThreadFenceReduce的缩减代码,这在中也有描述 在进行一些调试时,我发现只需插入一个额外的_syncthreads()调用,减少值就不再给出正确的总和: typedef int64_t SumType; template <int blockSize> static __device__ void reduceBlock( SumType mySum, const unsigned int tid ) {

我在CUDA示例中使用了改编自ThreadFenceReduce的缩减代码,这在中也有描述

在进行一些调试时,我发现只需插入一个额外的_syncthreads()调用,减少值就不再给出正确的总和:

typedef int64_t SumType;

template <int blockSize>
static __device__ void
reduceBlock(
    SumType mySum,
    const unsigned int tid
    )
{
    // Each thread puts its local sum into shared memory 
    extern __shared__ SumType sdata[];
    sdata[tid] = mySum;
    __syncthreads();

    // Sum values at an offset of 128 and 64
    if( blockSize >= 256 ) { if (tid < 128) { sdata[tid] = mySum = mySum + (sdata[tid + 128]); } __syncthreads(); }
    if( blockSize >= 128 ) { if (tid <  64) { sdata[tid] = mySum = mySum + (sdata[tid +  64]); } __syncthreads(); }

    if( tid < 32 )
    {
        __syncthreads(); //  <=== Extra __syncthreads(), breaks reduction!

        // Synchronize within warp using volatile type
        volatile SumType *smem = sdata;
        if( blockSize >= 64 ) { smem[tid] = mySum = mySum + (smem[tid + 32]); }
        if( blockSize >= 32 ) { smem[tid] = mySum = mySum + (smem[tid + 16]); }
        if( blockSize >= 16 ) { smem[tid] = mySum = mySum + (smem[tid +  8]); }
        if( blockSize >=  8 ) { smem[tid] = mySum = mySum + (smem[tid +  4]); }
        if( blockSize >=  4 ) { smem[tid] = mySum = mySum + (smem[tid +  2]); }
        if( blockSize >=  2 ) { smem[tid] = mySum = mySum + (smem[tid +  1]); }
    }
}
typedef int64_t SumType;
样板
静态设备无效
减速块(
乌龟,
常量无符号整数tid
)
{
//每个线程将其本地和放入共享内存
外部共享数据类型sdata[];
sdata[tid]=mySum;
__同步线程();
//偏移量为128和64时的和值
if(blockSize>=256){if(tid<128){sdata[tid]=mySum=mySum+(sdata[tid+128]);}
if(blockSize>=128){if(tid<64){sdata[tid]=mySum=mySum+(sdata[tid+64]);}
如果(tid<32)
{
__syncthreads();//=64{smem[tid]=mySum=mySum+(smem[tid+32]);}
如果(blockSize>=32){smem[tid]=mySum=mySum+(smem[tid+16]);}
如果(blockSize>=16){smem[tid]=mySum=mySum+(smem[tid+8]);}
如果(blockSize>=8){smem[tid]=mySum=mySum+(smem[tid+4]);}
如果(blockSize>=4){smem[tid]=mySum=mySum+(smem[tid+2]);}
如果(blockSize>=2){smem[tid]=mySum=mySum+(smem[tid+1]);}
}
}
为什么插入额外的uu syncthreads()会导致此代码不再工作

请参阅下面我的答案,了解一个独立的代码示例


编辑:在示例中将uu syncthreads()移动到if()语句中,以反映实际触发错误的代码。

该问题与仅为块中的某些线程调用u syncthreads()有关。最终的结果是一些非常奇怪的行为。 第B.6节:

__条件代码中允许使用syncthreads(),但前提是条件代码在整个线程块中的计算结果相同, 否则,代码执行可能会挂起或产生意外结果 副作用

我把它归结为以下简单的例子。共享内存s_onlyOneBlock中的标志由每个块中的一个线程设置;在块0中为真,而在其他块中为假。可以预期块0中的所有线程都会得到s_onlyOneBlock=true;但是,由于uu syncthreads()仅获取对线程0到31的调用,因此该行为是意外的:仅线程0到31获取s_onlyOneBlock=true:

#include <stdio.h>

static __global__ void
kernel()
{
    __shared__ bool s_onlyOneBlock;
    const unsigned int tid = threadIdx.x;

    // Call __syncthreads() for only some threads (don't do this!)
    if( tid < 32 )
        __syncthreads();

    // Thread 0 sets s_onlyOneBlock
    if( tid == 0 )
        s_onlyOneBlock = ( blockIdx.x == 0 );

    __syncthreads();

    if( s_onlyOneBlock )
    {
        // Only block 0 should reach this point
        if( tid==0 || tid==31 || tid==32 || tid==128 )
            printf("s_onlyOneBlock is TRUE:  block=%d thread=%d\n", blockIdx.x, threadIdx.x);
    }
    else
    {
        if( tid==0 || tid==31 || tid==32 || tid==128 )
            printf("s_onlyOneBlock is false: block=%d thread=%d\n", blockIdx.x, threadIdx.x);
    }
}

int main()
{
    kernel<<<2, 256>>>();
    cudaDeviceSynchronize();
}
#包括
静态\uuuu全局\uuuuu无效
内核()
{
__仅在eBlock上共享bool s_;
const unsigned int tid=threadIdx.x;
//仅为某些线程调用_syncthreads()(不要这样做!)
如果(tid<32)
__同步线程();
//线程0仅将s_设置为eBlock
如果(tid==0)
s_onlyOneBlock=(blockIdx.x==0);
__同步线程();
如果(仅限s_电子块)
{
//只有块0应到达此点
如果(tid==0 | | tid==31 | | tid==32 | | tid==128)
printf(“s_onlyOneBlock为TRUE:block=%d thread=%d\n”,blockIdx.x,threadIdx.x);
}
其他的
{
如果(tid==0 | | tid==31 | | tid==32 | | tid==128)
printf(“s_onlyOneBlock为false:block=%d thread=%d\n”,blockIdx.x,threadIdx.x);
}
}
int main()
{
内核();
cudaDeviceSynchronize();
}
结果是:

nvcc syncproblem.cu -o syncproblem
./syncproblem 
s_onlyOneBlock is false: block=0 thread=128  <--- should be true!
s_onlyOneBlock is false: block=1 thread=128
s_onlyOneBlock is false: block=0 thread=32   <--- should be true!
s_onlyOneBlock is false: block=1 thread=32
s_onlyOneBlock is TRUE:  block=0 thread=0
s_onlyOneBlock is TRUE:  block=0 thread=31
s_onlyOneBlock is false: block=1 thread=0
s_onlyOneBlock is false: block=1 thread=31
nvcc syncproblem.cu-o syncproblem
同步问题

s_onlyOneBlock为false:block=0 thread=128寻求调试帮助的问题(“为什么此代码不起作用?”)必须包括所需的行为、特定的问题或错误以及在问题本身中重现它所需的最短代码。没有明确问题陈述的问题对其他读者没有用处。请参阅:reduceBlock()调用方的输出在共享内存中,这是在示例中完成的。