Cuda 库达。数据组织

Cuda 库达。数据组织,cuda,Cuda,在我的应用程序中,每个线程都需要自己的数据矩阵。比方说,我有T线程,每个线程使用不同的矩阵D[M][N] 我的问题:如何组织数据结构 我的解决方案:我定义了一个由T*M*N元素组成的数组A。为了避免银行冲突,我首先为每个线程存储元素D[0][0]T次,然后存储D[0][1]D[0][M-1],D[1][0]等等(如果您像查看矩阵T*(M*N)一样查看此数组,每个线程将有一列)。通过这种方式,我在不同的内存库中为不同的线程提供了相同的元素。相应地,我通过以下方式访问线程x的元素D[I][j]:D[

在我的应用程序中,每个线程都需要自己的数据矩阵。比方说,我有
T
线程,每个线程使用不同的矩阵
D[M][N]

我的问题:如何组织数据结构

我的解决方案:我定义了一个由
T*M*N
元素组成的数组
A
。为了避免银行冲突,我首先为每个线程存储元素
D[0][0]
T
次,然后存储
D[0][1]
D[0][M-1]
D[1][0]
等等(如果您像查看矩阵
T*(M*N)
一样查看此数组,每个线程将有一列)。通过这种方式,我在不同的内存库中为不同的线程提供了相同的元素。相应地,我通过以下方式访问线程
x
的元素
D[I][j]
D[I][j](x)==A[T*(M*I+j)+x]

我的问题:计算复杂索引的计算成本很高


另外,我有英伟达特斯拉C2075(CUDA 2.0)。

你说M和N可以是几百。因此,您将无法大量使用共享内存(如果有的话)。你也可以仔细观察全局内存消耗(尽管特斯拉有很多内存)! 200x200 x 3584线程(我认为C2075的最小线程数)x sizeof(int)-这将产生547MB的数据

全局内存访问模式的工作方式不同。全局内存分为32、64和128B段。读取的成本大约是每个扭曲的不同段访问数。简言之,它通常归结为-你的访问越分散-越糟糕

因此,除非每个线程都在同一个索引上访问自己的矩阵(至少在大多数情况下),否则任何内存组织都是无效的。但是,如果上述情况属实,那么您描述的布局可能会起作用

此外,如果您分散了访问模式,禁用L1缓存可能会有所帮助。这是因为一级缓存线是128B,而二级缓存线只有32B,所以您可以减少过度抓取。至少-试试看:)

为了减轻访问阵列的痛苦,我将执行以下操作:

//let the kernel dimentions be known at compile time - you can safe some computation and registers
//assuming one-dimentional kernels

static const int blockSize = ...; //equivalent to blockDim
static const int gridSize = ...; //equivalent to gridDim
static const int rowSize = blockSize * gridSize;

template <typename T, int M, int N>
class MyMatrix {
private:
  T* data; //flattened array in global memory
  int tid;
public:
  __device__ inline MyMatrix(T* dataIsHere) : data(dataIsHere) {
    tid = threadIdx.x+blockDim.x*blockIdx.x;
  }
  __device__ inline T& operator()(int x, int y) {
    return data[(y*M+x)*rowSize+tid];
  }
}

//assuming the matrix size is 200x200 and consists of ints:

__global__ void myKernel(int* flattenedMatrices) {
  MyMatrix<int,200,200> matrix(flattenedMatrices);

  ...

  matrix(2,4) = .... // happily access the matrix for both loads and stores
} 
//让内核维度在编译时被知道-您可以保护一些计算和寄存器
//假设一维核
静态常量int blockSize=//相当于blockDim
静态常量int gridSize=//相当于gridDim
静态常量int rowSize=块大小*网格大小;
模板
类MyMatrix{
私人:
T*data;//全局内存中的扁平数组
国际贸易署;
公众:
__设备内联MyMatrix(T*DataISHER):数据(DataISHER){
tid=线程IDX.x+块DIM.x*块IDX.x;
}
__设备_uuu内联T和运算符()(int x,int y){
返回数据[(y*M+x)*行大小+tid];
}
}
//假设矩阵大小为200x200,由整数组成:
__全局无效myKernel(int*FlattedMatrices){
MyMatrix矩阵(平坦矩阵);
...
矩阵(2,4)=..//愉快地访问加载和存储的矩阵
} 

您提到了银行冲突。您是否打算将每个线程的每个D[M][N]存储在共享内存中?M和N的大致尺寸是多少?因为你已经把东西放平成了一个[],我不确定它在计算上会有多昂贵。你有没有看过PTX代码,看看编译器在做什么?如果每个线程都在访问一个连续的元素,那么从一个元素到下一个元素似乎只需要添加一个固定的偏移量。最多可能是一倍。如果相邻的线程元素是相邻的,您将有机会合并。您可能过度设计了您的解决方案。D矩阵是只读的吗?如果是这样,您可以使用内核参数列表中的
const
限定符来帮助处理银行冲突。通常,复制值以避免冲突可能会适得其反,因为这会降低L1和L2缓存的效率。只有在用分析器验证最简单的解决方案不是最优的情况下,才考虑更复杂的解决方案。这可能是因为您的算法是受计算限制的,将如何处理内存呈现为一个无意义的点。计算线程的当前矩阵是否需要矩阵元素?如果没有,则问题基本上是在
维度中按顺序执行像素操作。在这种情况下,我怀疑常量和共享内存都不会对您有所帮助。如果每列中的元素数大于每行中的元素数,那么您应该使用另一种方法来计算问题。M和N最多可以达到几百个,因此我使用全局内存。是的,我有这种扁平化,但我不喜欢它,我能以某种方式避免它吗?我对PTX代码不是很熟悉,你能给我一些链接吗,在那里我可以读到这些,并告诉我,查看PTX代码可以如何帮助我?我有一个乘法来计算索引,还有一个乘法来计算偏移量。罗杰,我也觉得这太过工程化了,但我看不出更好的方法。D不是只读的,我也没有复制值,每个矩阵都是不同的。我不喜欢复杂的解决方案,那么你认为最简单的解决方案是什么呢?非常感谢!我的实现看起来与您的代码非常相似(顺便问一下,
内联
内联
之间的区别是什么?)。我今天也尝试了未恢复的内存模式,其中每个矩阵都为某个线程串行存储,然后为下一个线程串行存储,以此类推。它的运行速度慢了好几倍:(我有了一个新想法:如果我为每行分配内存
N
次,将
N
指针传递到内核而不是一个,然后保存一个乘以元素的访问,你觉得怎么样?不值得你这么做。太多的编码可能会或可能不会为你节省一次操作(数百次).现在的编译器(包括nvcc)将通过在寄存器中存储和重用中间结果来尝试减少自己的操作数。