优化Intel Iris的OPENCL代码

时间:2015-08-07 13:13:40

标签: opencl intel gpgpu

我写了一个opencl代码片段,我想进一步改进:

global_size is 1920x1080
local size is kept NULL. I have left this to compiler.

__kernel void experiment(__read_only image2d_t YIn, __write_only image2d_t YOut)
{

  uint4 best_suited=0;
  uint4 temp =0;
  int best_sum,ssum;

    int2 coord_src = (int2)(get_global_id(0), 2*get_global_id(1)+1);

    const sampler_t smp = CLK_FILTER_NEAREST | CLK_NORMALIZED_COORDS_FALSE | CLK_ADDRESS_CLAMP_TO_EDGE;


      uint4 pixel1 = read_imageui(YIn, smp, coord_src + (int2)(-3,0));
      uint4 pixel2 = read_imageui(YIn, smp, coord_src + (int2)(-2,0));
      uint4 pixel3 = read_imageui(YIn, smp, coord_src + (int2)(-1,0));
      uint4 pixel4 = read_imageui(YIn, smp, coord_src + (int2)( 0,0));
      uint4 pixel5 = read_imageui(YIn, smp, coord_src + (int2)( 1,0));
      uint4 pixel6 = read_imageui(YIn, smp, coord_src + (int2)( 2,0));
      uint4 pixel7 = read_imageui(YIn, smp, coord_src + (int2)( 3,0));

      /* Read luma pixels of next line */                            
      uint4 pixel_nxt1 = read_imageui(YIn, smp, coord_src + (int2)(-3,2));
      uint4 pixel_nxt2 = read_imageui(YIn, smp, coord_src + (int2)(-2,2));
      uint4 pixel_nxt3 = read_imageui(YIn, smp, coord_src + (int2)(-1,2));
      uint4 pixel_nxt4 = read_imageui(YIn, smp, coord_src + (int2)( 0,2));
      uint4 pixel_nxt5 = read_imageui(YIn, smp, coord_src + (int2)( 1,2));
      uint4 pixel_nxt6 = read_imageui(YIn, smp, coord_src + (int2)( 2,2));
      uint4 pixel_nxt7 = read_imageui(YIn, smp, coord_src + (int2)( 3,2));

    /* main loop: */
    {

      best_sum= abs_diff(pixel3.x,pixel_nxt4.x) + abs_diff(pixel4.x,pixel_nxt5.x) + abs_diff(pixel5.x,pixel_nxt6.x) -8;
      best_suited.x = (pixel4.x+pixel_nxt2.x) >> 1;


      sum = abs_diff(pixel2.x,pixel_nxt2.x) + abs_diff(pixel3.x,pixel_nxt6.x) + abs_diff(pixel4.x,pixel_nxt1.x);

      if (sum < best_sum) 
      {

      best_sum = sum; 
        best_suited.x = (pixel3.x+pixel_nxt3.x) >> 1;

        sum = abs_diff(pixel1.x,pixel_nxt5.x) + abs_diff(pixel2.x,pixel_nxt6.x) + abs_diff(pixel3.x,pixel_nxt7.x) + 16;

        if (sum < best_sum) 
        {
             best_sum = sum; 
             best_suited.x = (pixel5.x+pixel_nxt1.x) >> 1;
        }
      } 

      sum = abs_diff(pixel4.x,pixel_nxt5.x) + abs_diff(pixel5.x,pixel_nxt2.x) + abs_diff(pixel6.x,pixel_nxt1.x);

      if (sum < best_sum) 
      {
       best_sum = sum; 
         best_suited.x = (pixel4.x+pixel_nxt3.x)>> 1;

         sum = abs_diff(pixel5.x,pixel_nxt3.x) + abs_diff(pixel6.x,pixel_nxt4.x) + abs_diff(pixel7.x,pixel_nxt3.x);

       if (sum < best_sum) 
       {
             best_sum = sum; 
             best_suited.x = (pixel6.x+pixel_nxt2.x) >> 1;
           }
      }
    }


      /* Pix4(0,0) is the current pixel in below calculations */
        write_imageui(YOut, coord_src, pixel4);
      /* store the result: */
      write_imageui(YOut, coord_src+(int2)(0,1),best_suited); 

}

我尝试过以下事项: 1)abs_diff是内置函数,用位代码替换abs_diff没有任何改进。

2)使用英特尔Vtune分析其性能,并看到执行单元闲置30%的时间。 GPU内存读取速度为7.6GB /秒,写入速度为3.942GB /秒。三级缓存未命中数接近177x10 ^ 9,计算线程接近35 lacs。采样器瓶颈也是8.3%。

进一步思考: 1)我不知道读取本地内存中的数据是否对我有利。由于本地内存缓存线访问与访问英特尔架构上的L3缓存相同。通过图像api进行读取我已经访问了图像对象的高速缓冲存储器,即纹理存储器。如果我编写类似这样的代码,我能想到的唯一帮助就是减少采样器瓶颈:     __local smem [256];    smem [get_local_id(0)= read_imageui(YIn,smp,coord_src);

2)我也不知道这里的最佳工作组规模应该是什么。

任何人都可以详细解释如何优化此代码吗?如何减少执行空闲时间,计算线程,L3缓存未命中以及增加GPU内存读写访问权限。如果你可以重新编写真正有用的代码。

1 个答案:

答案 0 :(得分:0)

1)我猜测本地记忆可能会有所帮助。即使它在L3中出局,如果你在SLM中仔细安排你的负载而不是让所有的EU同时锤击L3,你将获得更少的缓存捶打。如果你有时间进行实验,那至少值得一试。

2)在没有SLM的情况下,我建议在英特尔BDW上使用大型工作组(256或16x16,具体取决于您的方式)。这对于工作量少得多的短内核更为重要。对于像你这样的大型内核,它可能无关紧要。

如果您使用SLM路由,那么我们需要一个工作组大小,以便切片上的所有线程尽可能多地使用(但不能更多)。经验法则是每个工作项64字节。我认为这假设是SIMD16编译,但由于我们无法控制你可能最终编译SIMD8。因此,每个工作项目也尝试128个字节。请参阅this IDF presentation中的幻灯片34和44。