我在尝试从2D CUDA数组中检索矩阵元素A(m,n)时遇到了很多麻烦。有趣的是,当m = n时,我得到了正确的元素;即元素沿对角线。否则,我得到一些意想不到的行为:例如,如果我想获取元素A(13,12),并且我尝试使用tex2D(tex,row + 0.5f,col + 0.5f)检索它,我得到A (14,11)。据我所知,我正在尽我所能,所以我真的很想知道我哪里出错了。
内核如下。错误发生在前两个tex2D
调用之后,因此其余部分并不真正相关。
texture<float, 2, cudaReadModeElementType> tex_a;
texture<float, 2, cudaReadModeElementType> tex_b;
// Assume that BinaryFunc is multiplication, and AccumulationFunc is addition.
// Then this kernel computes the standard matrix product, and uses prefetching
// with tile sizes given by the template parameter TileSize.
template <unsigned TileSize, class T, class SizeType, class BinaryFunc,
class AccumulationFunc>
__global__ void
matrix_prod_tex_prefetch(T* c, const SizeType dim, BinaryFunc binary_func,
AccumulationFunc accum_func)
{
__shared__ T as[TileSize][TileSize];
__shared__ T bs[TileSize][TileSize];
SizeType row = blockIdx.y * TileSize + threadIdx.y;
SizeType col = blockIdx.x * TileSize + threadIdx.x;
T p = 0;
T l = tex2D(tex_a, row + 0.5f, threadIdx.x + 0.5f);
T m = tex2D(tex_b, threadIdx.y + 0.5f, col + 0.5f);
__syncthreads();
for (SizeType i = 1; i != dim / TileSize; ++i) {
as[threadIdx.y][threadIdx.x] = l;
bs[threadIdx.y][threadIdx.x] = m;
__syncthreads();
l = tex2D(tex_a, row + 0.5f, i * TileSize + threadIdx.x + 0.5f);
m = tex2D(tex_b, i * TileSize + threadIdx.y + 0.5f, col + 0.5f);
for (SizeType k = 0; k != TileSize; ++k) {
p = accum_func(p, binary_func(
as[threadIdx.y][k],
bs[k][threadIdx.x]
));
}
__syncthreads();
}
as[threadIdx.y][threadIdx.x] = l;
bs[threadIdx.y][threadIdx.x] = m;
__syncthreads();
for (SizeType k = 0; k != TileSize; ++k) {
p = accum_func(p, binary_func(
as[threadIdx.y][k],
bs[k][threadIdx.x]
));
}
c[dim * row + col] = p;
}
答案 0 :(得分:2)
答案:使用threadIdx.y交换threadIdx.x。最终,它归结为语义问题:纹理使用索引作为我们都熟悉的x轴和y轴的偏移。矩阵使用索引来引用行和列的索引。基本上,基础向量是交换的。
请注意,在为1D内存布局交换使用threadIdx.x和threadIdx.y可能会产生相同的结果时,您可能会在此过程中丢失合并的内存访问模式。