【问题标题】:lower occupancy - better performance更低的占用率 - 更好的性能
【发布时间】:2013-04-02 18:03:24
【问题描述】:

以下问题一直困扰着我。

使用两个不同的设备运行相同的内核,一个具有 1.3 的计算能力,另一个具有 2.0 的计算能力,在 1.3 中每个块的线程数更多(高占用率),但在 2.0 中,我获得了更好的性能。 2.0 的性能峰值似乎是每个块 16 个线程,占用率为 17% 任何小于或大于该点的任何东西都具有最差的性能。

因为这很可能是内核本身的性质造成的。

__global__ void
kernel_CalculateRFCH (int xstart, int ystart, int xsize,
          int ysize, int imxsize, int imysize, int *test, int *dev_binIm, int *per_block_results)
{
  int x2, y2, bin, bin2;
  __shared__ int s_pixels[blockDim.x*blockDim.y];  //this wouldn't compile in reailty

  int tx = threadIdx.x;
  int ty = threadIdx.y;
  int tidy = threadIdx.y + blockIdx.y * blockDim.y;
  int tidx = threadIdx.x + blockIdx.x * blockDim.x;

  if (xstart + xsize > imxsize)
    xsize = imxsize - xstart;
  if (ystart + ysize > imysize)
    ysize = imysize - ystart;

  s_pixels[tx * blockDim.y + ty] = 0;

  if (tidy >= ystart && tidy < ysize + ystart && tidx >= xstart && tidx < xsize + xstart)
{
      bin = dev_binIm[tidx + tidy * imxsize];

      if (bin >= 0)
    {
      x2 = tidx;
      y2 = tidy;

         while (y2 < ystart + ysize)
          {
          if (x2 >= xstart + xsize || x2 - tidx > 10)
             {
                  x2 = xstart;
                  y2++;
                  if (tidx - x2 > 10)
                   x2 = tidx - 10;
                  if (y2 - tidy > 10)
                   {
                      y2 = ystart + ysize;
                      break;
                   }
                   if (y2 >= ystart + ysize)
                      break;
              }

          bin2 = dev_binIm[x2 + y2 * imxsize];

           if (bin2 >= 0)
              {
               test[(tidx + tidy * imxsize) * 221 + s_pixels[tx * blockDim.y + ty]] = bin + bin2 * 80;
               s_pixels[tx * blockDim.y + ty]++;
              }
          x2++;
        }           
     }          

  } 

  for (int offset = (blockDim.x * blockDim.y) / 2; offset > 0; offset >>= 1)
    {
     if ((tx * blockDim.y + ty) < offset)
       {
         s_pixels[tx * blockDim.y + ty] += s_pixels[tx * blockDim.y + ty + offset];
       }
      __syncthreads ();
     }

   if (tx * blockDim.y + ty == 0)
     {
        per_block_results[blockIdx.x * gridDim.y + blockIdx.y] = s_pixels[0];

     }

}

我使用二维线程。

ptxas 信息:为“sm_10”编译入口函数“_Z20kernel_CalculateRFCHiiiiiiPiS_” ptxas 信息:使用了 16 个寄存器,128 字节 smem,8 字节 cmem[1] .

每个设备的每个案例中都显示了 16 个寄存器。

任何关于为什么会发生这种情况的想法都会非常有启发性。

【问题讨论】:

  • 你知道Vasily Volkov的工作吗?您的问题标题很容易让人联想到他的“better performance at lower occupancy”演示文稿。
  • 每个块的线程数是确定占用率的一个因素,但没有直接关系,因此增加每个块的线程数会增加占用率(正如您所发现的,占用率和性能要么)。使用Occupancy Calculator 找出内核的占用情况。
  • 最后,每个块 16 个线程太少了,因为线程被安排在 32 个线程的 warps 中。因此,仅使用 16 个线程仅使用一半的可用资源(可能由于其他原因甚至更少,好的块大小通常在每个块 64..256 个线程之间)。您确定没有互换“每个块的线程数”和“块数”参数吗?
  • 我没有交换论据。正如我从占用计算器中看到的那样,当我增加每个块占用的线程时,占用率也会增加,反之亦然。对于 1.3 设备,当我使用 100% 的占用率时,我会获得更好的性能。当我使用 17%(每块 16 个线程)占用率时使用 2.0 设备,我获得了最佳性能。小于或大于此的占用率会产生最差的性能。不需要说当我减少每个块的线程数时,我的内核的块数必须增加。为什么会在 2.0 而不是 1.3 上发生这种情况?
  • 我在两点上都同意 tera:1. 在较低的入住率下获得更好的性能并不是一个闻所未闻的概念。 2. 在 cc 2.0 设备上每块 16 个线程而不是 32 或 32 倍数的更好性能似乎不太可能。

标签: performance cuda


【解决方案1】:

除了上面的一般性评论之外,您的内核是一个非常特殊的情况,因为大多数线程根本不做任何工作。为什么不直接将xstartystart 添加到tidxtidy 并选择更小的网格?您在较小块大小上的更好性能可能只是感兴趣区域如何分割成块的人工制品。

这也解释了为什么您会发现计算能力 1.x 设备与 CC 2.0+ 设备之间存在巨大差异。从 CC 2.0 开始,Nvidia GPU 在处理运行时在块之间差异很大的内核方面已经变得更好。
在计算能力 1.x 上,只有在所有当前运行的块都完成后才会安排新的块浪潮,而从 CC 2.0 开始,只要任何旧块完成,就会启动新块。

【讨论】:

  • 实际上大部分线程都在做这项工作,数组 dev_binIm 的大小为 307200,大约有 280000 个值为 0 或正数。不要把 xstart、ystart、xsize、ysize 放在首位。网格尺寸是为它们精确计算的。每个维度都完全符合这些值,并且 xstart 和 ystart 为 0。我是否将它们从内核中删除并不重要 - 计算方面。
猜你喜欢
  • 1970-01-01
  • 2011-09-19
  • 2015-03-14
  • 1970-01-01
  • 1970-01-01
  • 2010-10-20
  • 2010-09-21
  • 2020-03-02
  • 2014-11-30
相关资源
最近更新 更多