OpenCL全局内存提取

时间:2012-03-28 17:06:24

标签: opencl gpgpu

我正在考虑重新设计我的GPU OpenCL内核以加快速度。问题是有很多全局内存没有合并,并且提取实际上降低了性能。因此,我计划将尽可能多的全局内存复制到本地,但我必须选择要复制的内容。

现在我的问题是:许多小块内存会不会比较少的大块内存受到伤害?

3 个答案:

答案 0 :(得分:5)

您可以使用clGetDeviceInfo找出设备的缓存行大小。 (clGetDeviceInfo,CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE)在今天的许多设备上,此值通常为16个字节。

小读取可能很麻烦,但如果您从同一个高速缓存行读取,则应该没问题。简短的回答:你需要将你的“小块”保持在内存中以保持快速。

下面我有两个函数来演示访问内存的两种方法 - vectorAddFoo和vectorAddBar。第三个函数copySomeMemory(...)专门适用于您的问题。两个向量函数都将其工作项添加到要添加的向量的一部分,但使用不同的内存访问模式。 vectorAddFoo获取每个工作项来处理一个向量元素块,从它在数组中计算的位置开始,然后向前移动它的工作量。 vectorAddBar的工作项从它们的gid开始,并在获取和添加下一个元素之前跳过gSize(=全局大小)元素。

vectorAddBar将执行得更快,因为读写会落入内存中的同一个高速缓存行。每4次浮点读取将落在同一个高速缓存行上,并且只从内存控制器执行一次操作。在这个问题上阅读了[]和b []之后,所有四个工作项都可以进行添加,并将其写入c []排队。

vectorAddFoo将保证读取和写入不在同一个高速缓存行中(除了非常短的向量~totalElements< 5)。每次从工作项中读取都需要来自内存控制器的操作。除非gpu在每种情况下缓存以下3个浮点数,否则将导致4倍的内存访问。

__kernel void  
vectorAddFoo(__global const float * a,  
          __global const float * b,  
          __global       float * c,
          __global const totalElements) 
{ 
  int gid = get_global_id(0); 
  int elementsPerWorkItem = totalElements/get_global_size(0);
  int start = elementsPerWorkItem * gid;

  for(int i=0;i<elementsPerWorkItem;i++){
    c[start+i] = a[start+i] + b[start+i]; 
  }
} 
__kernel void  
vectorAddBar(__global const float * a,  
          __global const float * b,  
          __global       float * c,
          __global const totalElements) 
{ 
  int gid = get_global_id(0); 
  int gSize = get_global_size(0);

  for(int i=gid;i<totalElements;i+=gSize){
    c[i] = a[i] + b[i]; 
  }
} 
__kernel void  
copySomeMemory(__global const int * src,
          __global const count,
          __global const position) 
{ 
  //copy 16kb of integers to local memory, starting at 'position'
  int start = position + get_local_id(0); 
  int lSize = get_local_size(0);
  __local dst[4096];
  for(int i=0;i<4096;i+=lSize ){
    dst[start+i] = src[start+i]; 
  }
  barrier(CLK_GLOBAL_MEM_FENCE);
  //use dst here...
} 

答案 1 :(得分:1)

一般而言,较大尺寸的fecthes将更有效。在没有看到您的代码的情况下,我无法向您提供具体建议,但请确保从工作项中访问顺序块以启用“流式传输”。将数据带入本地存储器后,请进行任何转置或随机存储器访问。

答案 2 :(得分:0)

我无法正确理解你的问题,但是如果你有大量的全局访问权限,并且如果重复使用这些问题而不是使用本地内存。

注意:小的本地工作量会减少共享的数据,所以没有用, 大型本地工作量减少并行线程。所以你需要选择最好的一个。