使用ALEA库循环GPULaunch或内核

时间:2017-01-29 17:57:31

标签: c# gpu aleagpu

我需要使用一个整数(0-99)作为参数,使用相同的数据运行我的GPU内核(ALEA库)100次。我试图在内核中实现这个循环但是我得到了奇怪的结果。我不得不把循环从内核和GPULaunch函数中取出来:

var lp = new LaunchParam(GridDim, BlockDim);
for (int i= 0; i < 100; i++)
{
   GPULaunch(TestKernel, lp, Data, i);
}

代码的CPU版本经过高度优化,可有效使用4个内核(%100)。根据合并的内存访问原则重新组织内存中的数据后,我可以拥有%92占用率和%96全局负载效率。但是,GPU版本仅比CPU版本快50%。我怀疑循环GPULaunch是否有效。

如下图所示,我在NVIDIA Visual Profilier中看不到重复的内存传输。一旦我将数据加载到GPU(图中没有看到但对我来说不重要),我会得到100个循环输出的短暂内存传输,如右端所示。所以我的问题是:

  1. 这种在循环中调用GPULaunch的方法是否有相同数据的看不见的内存传输?
  2. 如果有这样的开销,我需要在内核中使用此循环。我该怎么做。我试过但结果不稳定,认为这种方法不适合GPU并行编程架构。
  3. 提前致谢

    NVIdia Visual Profiler resutl

1 个答案:

答案 0 :(得分:0)

我试图再次在内核中实现循环并且它有效。我不确定这次有什么不同。这是明显的代码(只是模板而不是工作代码):

public class GPUModule : ILGPUModule
{

  public GPUModule (GPUModuleTarget target) : base(target)
  {
  }

  [Kernel]
  Public MyKernel(deviceptr<int> Data)
  {
    var start = blockIdx.x * blockDim.x + threadIdx.x;
    int ind = threadIdx.x;

    for (int i=0;i<100;i++)
    {
      //Kernel Code here
    }
  }

  public void Dilimle_VerilerB(deviceptr<int> Data
  {
    ...
    var lp = new LaunchParam(GridDim, BlockDim);
    GPULaunch(TestKernel, lp, Data, HOIndex);
    ...
  }
}

内核的唯一补充是整数“i”上的循环。不幸的是,它导致寄存器/线程计数从26跳到42,导致占用率从%100下降到%50,这使执行时间从2.1秒略微增加到2.3秒。因此,如果维持%100占用率,将循环带入内核将提高性能,从而大大消除了GPULaunch开销。

围绕GPULaunch循环的%100占用率正在使用1024个线程/块。更改为内核循环后,我将其更改为128个线程/块。这将Ocuppancy增加到%62并导致执行时间为1.1秒。因此,作为结论,将这样的循环引入内核可以使GPU性能提高2倍。

所以问题是为什么内核的寄存器/线程数从26增加到42,并且向内核添加一个整数循环。如果寄存器数量大约为30,我认为占用率仍然接近%100。