故意造成CUDA设备上共享内存的银行冲突
cuda设备上的共享内存如何工作对我来说是个谜。我很想计算访问同一共享内存的线程数。为此,我编写了一个简单的程序故意造成CUDA设备上共享内存的银行冲突,cuda,gpu,shared-memory,bank-conflict,Cuda,Gpu,Shared Memory,Bank Conflict,cuda设备上的共享内存如何工作对我来说是个谜。我很想计算访问同一共享内存的线程数。为此,我编写了一个简单的程序 #include <cuda_runtime.h> #include <stdio.h> #define nblc 13 #define nthr 1024 //------------------------@device-------------------- __device__ int inwarpD[nblc]; __global__ voi
#include <cuda_runtime.h>
#include <stdio.h>
#define nblc 13
#define nthr 1024
//------------------------@device--------------------
__device__ int inwarpD[nblc];
__global__ void kernel(){
__shared__ int mywarp;
mywarp=0;
for (int i=0;i<5;i++) mywarp += (10000*threadIdx.x+1);
__syncthreads();
inwarpD[blockIdx.x]=mywarp;
}
//------------------------@host-----------------------
int main(int argc, char **argv){
int inwarpH[nblc];
cudaSetDevice(2);
kernel<<<nblc, nthr>>>();
cudaMemcpyFromSymbol(inwarpH, inwarpD, nblc*sizeof(int), 0, cudaMemcpyDeviceToHost);
for (int i=0;i<nblc;i++) printf("%i : %i\n",i, inwarpH[i]);
}
相反,我期待着
523776*10000+5*1024=5237765120
每一个街区。有人能解释一下我对共享内存的理解在哪里失败了吗。我还想知道一个块中的所有线程如何访问(更新)相同的共享变量。我知道在同一个MP循环中是不可能的。序列化对我来说很好,因为这将是一个罕见的事件。让我们看看它生成的ptx
//Declare some registers
.reg .s32 %r<5>;
.reg .s64 %rd<4>;
// demoted variable
.shared .align 4 .u32 _Z6kernelv$__cuda_local_var_35411_30_non_const_mywarp;
//load tid in register r1
mov.u32 %r1, %tid.x;
//multiple tid*5000+5 and store in r2
mad.lo.s32 %r2, %r1, 50000, 5;
//store result in shared memory
st.shared.u32 [_Z6kernelv$__cuda_local_var_35411_30_non_const_mywarp], %r2;
///synchronize
bar.sync 0;
//load from shared memory and store in r3
ld.shared.u32 %r3, [_Z6kernelv$__cuda_local_var_35411_30_non_const_mywarp];
mov.u32 %r4, %ctaid.x;
mul.wide.u32 %rd1, %r4, 4;
mov.u64 %rd2, inwarpD;
add.s64 %rd3, %rd2, %rd1;
//store r3 in global memory
st.global.u32 [%rd3], %r3;
ret;
所以你没有遇到银行冲突。你正在经历一场比赛。你说得对,我不知道我昨天在想什么。谢谢你的提醒,谢谢你的分析。有些事情我仍然不清楚:i)当我放置volatile属性时(正如您在第一个答案中所建议的),它会稍微改变输出,例如,最后一位数字不是5,但有时是7,8。ii)是否通过只允许一个线程修改mywarp变量来解决争用条件?iii)如果我希望所有线程都参与,我需要atomicAdd()?这完全取决于您需要什么。如果您需要一个简单的缩减(跨线程求和),您可以将数据保留在寄存器中,然后在共享内存中使用缩减方法。如果需要每个扭曲唯一地更新单个值,那么是的,需要使用atomicAdd。
//Declare some registers
.reg .s32 %r<5>;
.reg .s64 %rd<4>;
// demoted variable
.shared .align 4 .u32 _Z6kernelv$__cuda_local_var_35411_30_non_const_mywarp;
//load tid in register r1
mov.u32 %r1, %tid.x;
//multiple tid*5000+5 and store in r2
mad.lo.s32 %r2, %r1, 50000, 5;
//store result in shared memory
st.shared.u32 [_Z6kernelv$__cuda_local_var_35411_30_non_const_mywarp], %r2;
///synchronize
bar.sync 0;
//load from shared memory and store in r3
ld.shared.u32 %r3, [_Z6kernelv$__cuda_local_var_35411_30_non_const_mywarp];
mov.u32 %r4, %ctaid.x;
mul.wide.u32 %rd1, %r4, 4;
mov.u64 %rd2, inwarpD;
add.s64 %rd3, %rd2, %rd1;
//store r3 in global memory
st.global.u32 [%rd3], %r3;
ret;
for (int i=0;i<5;i++)
mywarp += (10000*threadIdx.x+1);
mywarp=50000*threadIdx.x+5