繁体   English   中英

需要优化的CUDA内核

[英]A CUDA kernel to optimize

嗨,我最近有一个CUDA内核需要优化。 这是原始的CUDA内核:

__glboal__ void kernel_base( float *data, int x_dim, int y_dim )
{
  int ix  = blockIdx.x;
  int iy  = blockIdx.y*blockDim.y + threadIdx.y;
  int idx = iy*x_dim + ix;
  float tmp = data[idx];

  if( ix % 2 )
  {
    tmp += sqrtf( sinf(tmp) + 1.f );
  }
  else
  {
     tmp += sqrtf( cosf(tmp) + 1.f );
  }
  data[idx] = tmp;
}


dim3 block( 1, 512 );
dim3 grid( 2048/1, 2048/512 );
kernel<<<grid,block>>>( d_data, 2048, 2048 );

这里的基本问题是内存合并和线程分歧的困境。 原始代码在主列中处理数组,因此它跨越了内存访问模式,但是没有差异。 我可以将其更改为行优先,这又有线程发散的问题。

那么,有谁有更好的主意如何最大化性能呢?

与跨内存访问相比,就性能而言,这里的线程分歧并不是一个大问题。 我会合并。 此外,您的数据存储具有隐式AoS顺序。 如果可以将数据重新排序到SoA,则可以解决这两个问题。

因此,我将对该内核进行重新排序,使其首先以行主要方式处理事物。 这解决了合并问题,但引入了翘曲发散。

如果您无法重新排序数据,那么我将考虑通过修改索引方案来消除扭曲差异,以便偶数扭曲处理偶数元素,奇数扭曲处理奇数元素。

这将消除翘曲发散,但会再次破坏完美的合并,但是缓存应有助于解决此问题。 在Fermi的情况下,L1缓存应该可以很好地平滑此模式。 然后,我将把这种情况与翘曲的发散情况进行比较,看哪个更快。

考虑到

sin(x) = cos(x + pi/2)

因此,您可以将if ... else条件替换为

tmp += sqrtf( cosf(tmp + (ix%2) * pi/2) + 1.f );

避免分支分歧。

如果执行此操作,则可以将块尺寸设置为16 x 16或其他一些具有较低长宽比的形状。 我将使用共享内存来抓取2个块的数据(每个idx从数据中抓取2个元素,可能由blockDim.x元素分隔),然后让每个块执行其分配的“奇数”行,后跟“偶数”行。 您将不得不重新计算ix和iy(可能还有idx),并且将使用1/2的块,但是应该有合并的内存访问,后跟无差异的代码。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM