我遇到了一个奇怪的问题,至少在我看来它看起来很奇怪,而且我希望有人能够对它有所了解。我有一个CUDA内核,它依赖于共享内存来进行快速本地访问。据我所知,如果半warp中的所有线程都访问相同的共享内存库,那么该值将被广播到warp中的线程。此外,从多个warp访问同一个bank不会导致银行冲突,它们只会被序列化。牢记这一点,我已经创建了一个小内核来测试它(在遇到原始内核中的问题之后)。这是片段:
#define NUM_VALUES 16
#define NUM_LOOPS 1024
__global__ void shared_memory_test(float *output)
{
// Create some shared memory
__shared__ int dm_delays[NUM_VALUES];
// Loop over NUM_LOOPS
float accumulator = 0;
for(unsigned c = 0; c < NUM_LOOPS; c++)
{
// Force shared memory update
for(int d = threadIdx.x; d < NUM_VALUES; d++)
dm_delays[d] = c * d;
// __syncthreads();
for(int d = 0; d < NUM_VALUES; d++)
accumulator += dm_delays[d];
}
// Store accumulated value to global memory
for(unsigned d = 0; d < NUM_VALUES; d++)
output[d] = accumulator;
}
我运行它的块大小为16(一半经线,效率不是很高,但仅用于测试目的)。所有线程都应该寻址相同的共享内存库,因此不应该有冲突。然而,相反的情况似乎是正确的。我在Visual Studio 2010上使用Parallel Nsight进行此测试。
对我来说更神秘的是,如果我在外部循环中取消注释__syncthreads
调用,那么银行冲突的数量会急剧增加。
只是一些数字给你一个想法(这是一个网格包含一个16个线程的块,所以一个半warp,NUM_VALUES = 16,NUM_LOOPS = 1024):
__syncthreads
:4次银行冲突__syncthreads
:4,096次银行冲突我在GTX 670上运行它,设置为compute_capability 3.0
提前谢谢
更新:有人指出,没有__syncthreads
,外部循环中的NUM_LOOPS读取被编译器优化掉,因为dm_delays的值永远不会改变。现在我在这两种情况下都会得到一个持续的4,096个银行冲突,这对于共享内存的广播行为仍然不能很好。
答案 0 :(得分:0)
由于dm_delays
的值没有改变,这可能是如果__syncthreads
不存在,编译器会优化1024次读取到共享内存的情况。使用__syncthreads
,它可能会假设该值可能被另一个线程更改,因此它会一遍又一遍地读取该值。