C++ CUDA中记忆聚合的双重检验理解

C++ CUDA中记忆聚合的双重检验理解,c++,cuda,C++,Cuda,假设我定义了一些GPU可见的阵列: double* doubleArr = createCUDADouble(fieldLen); float* floatArr = createCUDAFloat(fieldLen); char* charArr = createCUDAChar(fieldLen); 现在,我有以下CUDA线程: void thread(){ int o = getOffset(); // the same for all threads in launch dou

假设我定义了一些GPU可见的阵列:

double* doubleArr = createCUDADouble(fieldLen);
float* floatArr = createCUDAFloat(fieldLen);
char* charArr = createCUDAChar(fieldLen);
现在,我有以下CUDA线程:

void thread(){
  int o = getOffset(); // the same for all threads in launch
  double d = doubleArr[threadIdx.x + o];
  float f = floatArr[threadIdx.x + o];
  char c = charArr[threadIdx.x + o];
}

我不太确定我是否正确解释了文档,这对我的设计非常关键:double、float和char的内存访问是否会很好地结合起来?(猜测:是的,它将适合
sizeof(type)*blockSize.x/(事务大小)
事务,加上上上下边界的一个额外事务。)

是的,对于您所展示的所有情况,假设
createCUDAxxxxx
转换为某种普通的
Cudamaloc
类型操作,一切都应该很好地结合起来

如果我们有通过
cudamaloc
分配的普通1D设备阵列,一般来说,如果我们的加载模式包括以下形式的阵列索引,我们应该具有良好的跨线程聚合行为:

data_array[some_constant + threadIdx.x];
实际上,数组的数据类型并不重要,它将很好地结合在一起

但是,从性能角度来看,全局加载(假设L1未命中)将以最小128字节的粒度发生。因此,每个线程加载较大的大小(例如,
int
float
double
float4
,等等)可能会提供稍好的性能。如果负载跨越足够多的扭曲,缓存往往会减少任何差异

在一段特定的代码上用一个。根据您选择的探查器,有许多方法可以实现这一点,但例如,使用nvprof,您可以做到:

nvprof --metric gld_efficiency ./my_exe
它将返回一个平均百分比数字,该数字或多或少准确地反映了在全局负载上发生的最佳合并的百分比

这是我通常引用的关于内存优化的其他背景信息的演示

我想有人会注意到这种模式:

data_array[some_constant + threadIdx.x];

大致对应于上述演示文稿幻灯片40-41中显示的访问类型。啊哈!!效率下降到50%-80%。这是正确的,如果只考虑单个扭曲载荷。但是,参考幻灯片40,我们看到“第一次”加载将需要加载两条缓存线。然而,在此之后,额外的加载(为了简单起见,向右移动)将只需要每个扭曲加载一个额外的/新的缓存线(假设存在一级或二级缓存,以及合理的局部性,即缺少抖动)。因此,在一个相当大的数组(超过128字节)上,平均每个扭曲需要一条新的缓存线,这相当于100%的效率。

我不明白为什么这个问题会被否决。它违反了什么规则,或者我需要改进什么?只有大约10^99个关于记忆聚合的问题,其中许多问题包括文档和演示的链接,以帮助澄清它们的解释。看看你的问题,首先你不能让数组“对GPU可见”如下:
double*doubleArr=newdouble[fieldLen]
Next,
getOffset
是否依赖于任何内置变量,例如
threadIdx.x
?总的来说,这个问题看起来很像是在开拓SoA与AoS的相同领域。除非说明如何访问结构,否则无法回答结构问题。您正在加载
char
char3
数量吗?顺便说一句,我没有否决您的问题。我可以很容易地证明;-)好的,那很有帮助。所以我试图解决这个问题。