我有一个关于合并cuda访问的基本问题。
例如,我有一个32个元素的数组和32个线程,每个线程访问一个元素。
__global__ void co_acc ( int A[32], int B[32] ) {
int inx = threadIdx.x + (gridDim.x * blockDim.x);
B[inx] = A[inx]
}
现在,我想知道:如果我有32个线程,但是有64个元素的数组,每个线程必须复制2个元素。为了保持合并访问,我应该转移
我拥有的线程数的数组访问索引。
例如:ID为0的线程将访问A[0]
和A[0+32]
。我对这个假设是对的吗?
__global__ void co_acc ( int A[64], int B[64] ) {
int inx = threadIdx.x + (gridDim.x * blockDim.x);
int actions = 64/blockDim.x;
for ( int i = 0; i < actions; ++i )
B[inx+(i*blockDim.x)] = A[inx+(i*blockDim.x)]
}
答案 0 :(得分:2)
为了保持合并访问,我应该将数组访问的索引移动我拥有的线程数。例如:ID为0的线程将访问A [0]和A [0 + 32]。我对这个假设是对的吗?
是的,这是一种正确的方法。
严格来说,它不是 而是可以:只要warp请求中的所有线程都在同一个内部(对齐),任何内存访问都将被合并128字节的行。这意味着你可以置换线程索引,你的访问仍然会被合并(但是为什么你做的很简单时会很复杂)。
另一个解决方案是让每个线程加载int2
:
__global__ void co_acc ( int A[64], int B[64] ) {
int inx = threadIdx.x + (gridDim.x * blockDim.x);
reinterpret_cast<int2*>(B)[inx] = reinterpret_cast<int2*>(A)[inx];
}
这是(在我看来)更简单和更清晰的代码,可能提供稍微更好的性能,因为这可能会减少编译器发出的指令数量和内存请求之间的延迟(免责声明:I没有尝试过。)
注意:正如Robert Crovella在评论中提到的,如果你真的使用了32个线程的线程块,那么你可能会严重低估GPU的容量。